patrol 0.0.4 → 0.1.0.1
raw patch · 127 files changed
+5290/−622 lines, 127 filesdep +exceptionsdep +hspecdep +patroldep ~aesondep ~basedep ~bytestringPVP ok
version bump matches the API change (PVP)
Dependencies added: exceptions, hspec, patrol
Dependency ranges changed: aeson, base, bytestring, containers, http-client, network-uri, text, time, uuid
API changes (from Hackage documentation)
- Patrol: data StackTrace
- Patrol: data Timestamp
- Patrol.Type.Dsn: fromString :: String -> Either String Dsn
- Patrol.Type.Dsn: toString :: Dsn -> String
- Patrol.Type.Dsn: toUri :: Dsn -> URI
- Patrol.Type.EventId: data EventId
- Patrol.Type.EventId: toUuid :: EventId -> UUID
- Patrol.Type.Exception: [stackTrace] :: Exception -> Maybe StackTrace
- Patrol.Type.Response: [id_] :: Response -> EventId
- Patrol.Type.StackTrace: StackTrace :: NonEmpty Frame -> StackTrace
- Patrol.Type.StackTrace: [frames] :: StackTrace -> NonEmpty Frame
- Patrol.Type.StackTrace: fromCallStack :: CallStack -> Maybe StackTrace
- Patrol.Type.StackTrace: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.StackTrace.StackTrace
- Patrol.Type.StackTrace: instance GHC.Classes.Eq Patrol.Type.StackTrace.StackTrace
- Patrol.Type.StackTrace: instance GHC.Show.Show Patrol.Type.StackTrace.StackTrace
- Patrol.Type.StackTrace: newtype StackTrace
- Patrol.Type.Timestamp: data Timestamp
- Patrol.Type.Timestamp: fromUtcTime :: UTCTime -> Timestamp
- Patrol.Type.Timestamp: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.Timestamp.Timestamp
- Patrol.Type.Timestamp: instance GHC.Classes.Eq Patrol.Type.Timestamp.Timestamp
- Patrol.Type.Timestamp: instance GHC.Show.Show Patrol.Type.Timestamp.Timestamp
- Patrol.Type.Timestamp: toUtcTime :: Timestamp -> UTCTime
- Patrol.Type.User: [id_] :: User -> Maybe Text
- Patrol.Utility.Json: pair :: (ToJSON value, KeyValue pair) => String -> value -> pair
- Patrol.Utility.Json: required :: FromJSON value => Object -> String -> Parser value
- Patrol.Utility.Maybe: note :: e -> Maybe a -> Either e a
+ Patrol: data AppContext
+ Patrol: data AppleDebugImage
+ Patrol: data Breadcrumb
+ Patrol: data BreadcrumbType
+ Patrol: data Breadcrumbs
+ Patrol: data BrowserContext
+ Patrol: data CError
+ Patrol: data ClientSdkInfo
+ Patrol: data ClientSdkPackage
+ Patrol: data Context
+ Patrol: data DebugImage
+ Patrol: data DebugMeta
+ Patrol: data DeviceContext
+ Patrol: data ErrorType
+ Patrol: data EventProcessingError
+ Patrol: data EventType
+ Patrol: data Exceptions
+ Patrol: data Geo
+ Patrol: data GpuContext
+ Patrol: data LogEntry
+ Patrol: data MachException
+ Patrol: data Mechanism
+ Patrol: data MechanismMeta
+ Patrol: data NativeDebugImage
+ Patrol: data NsError
+ Patrol: data OsContext
+ Patrol: data PosixSignal
+ Patrol: data Problem
+ Patrol: data ProguardDebugImage
+ Patrol: data RuntimeContext
+ Patrol: data SpanStatus
+ Patrol: data Stacktrace
+ Patrol: data SystemSdkInfo
+ Patrol: data Thread
+ Patrol: data Threads
+ Patrol: data TraceContext
+ Patrol: data TransactionInfo
+ Patrol: data TransactionSource
+ Patrol.Constant: applicationJson :: ByteString
+ Patrol.Constant: sentryVersion :: Text
+ Patrol.Constant: userAgent :: Text
+ Patrol.Constant: xSentryAuth :: HeaderName
+ Patrol.Exception.Problem: Problem :: String -> Problem
+ Patrol.Exception.Problem: instance GHC.Classes.Eq Patrol.Exception.Problem.Problem
+ Patrol.Exception.Problem: instance GHC.Exception.Type.Exception Patrol.Exception.Problem.Problem
+ Patrol.Exception.Problem: instance GHC.Show.Show Patrol.Exception.Problem.Problem
+ Patrol.Exception.Problem: newtype Problem
+ Patrol.Extra.Aeson: intoObject :: [Pair] -> Value
+ Patrol.Extra.Aeson: isEmpty :: Value -> Bool
+ Patrol.Extra.Aeson: pair :: ToJSON a => String -> a -> Pair
+ Patrol.Extra.List: insert :: Eq k => (k, v) -> [(k, v)] -> [(k, v)]
+ Patrol.Extra.List: insertAll :: Eq k => [(k, v)] -> [(k, v)] -> [(k, v)]
+ Patrol.Extra.List: insertBy :: (a -> a -> Bool) -> a -> [a] -> [a]
+ Patrol.Type.AppContext: AppContext :: Text -> Text -> Maybe Int -> Text -> Maybe UTCTime -> Text -> Text -> Text -> AppContext
+ Patrol.Type.AppContext: [appBuild] :: AppContext -> Text
+ Patrol.Type.AppContext: [appIdentifier] :: AppContext -> Text
+ Patrol.Type.AppContext: [appMemory] :: AppContext -> Maybe Int
+ Patrol.Type.AppContext: [appName] :: AppContext -> Text
+ Patrol.Type.AppContext: [appStartTime] :: AppContext -> Maybe UTCTime
+ Patrol.Type.AppContext: [appVersion] :: AppContext -> Text
+ Patrol.Type.AppContext: [buildType] :: AppContext -> Text
+ Patrol.Type.AppContext: [deviceAppHash] :: AppContext -> Text
+ Patrol.Type.AppContext: data AppContext
+ Patrol.Type.AppContext: empty :: AppContext
+ Patrol.Type.AppContext: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.AppContext.AppContext
+ Patrol.Type.AppContext: instance GHC.Classes.Eq Patrol.Type.AppContext.AppContext
+ Patrol.Type.AppContext: instance GHC.Show.Show Patrol.Type.AppContext.AppContext
+ Patrol.Type.AppleDebugImage: AppleDebugImage :: Text -> Maybe Int -> Maybe Int -> Text -> Maybe Int -> Text -> Text -> Text -> AppleDebugImage
+ Patrol.Type.AppleDebugImage: [arch] :: AppleDebugImage -> Text
+ Patrol.Type.AppleDebugImage: [cpuSubtype] :: AppleDebugImage -> Maybe Int
+ Patrol.Type.AppleDebugImage: [cpuType] :: AppleDebugImage -> Maybe Int
+ Patrol.Type.AppleDebugImage: [imageAddr] :: AppleDebugImage -> Text
+ Patrol.Type.AppleDebugImage: [imageSize] :: AppleDebugImage -> Maybe Int
+ Patrol.Type.AppleDebugImage: [imageVmaddr] :: AppleDebugImage -> Text
+ Patrol.Type.AppleDebugImage: [name] :: AppleDebugImage -> Text
+ Patrol.Type.AppleDebugImage: [uuid] :: AppleDebugImage -> Text
+ Patrol.Type.AppleDebugImage: data AppleDebugImage
+ Patrol.Type.AppleDebugImage: empty :: AppleDebugImage
+ Patrol.Type.AppleDebugImage: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.AppleDebugImage.AppleDebugImage
+ Patrol.Type.AppleDebugImage: instance GHC.Classes.Eq Patrol.Type.AppleDebugImage.AppleDebugImage
+ Patrol.Type.AppleDebugImage: instance GHC.Show.Show Patrol.Type.AppleDebugImage.AppleDebugImage
+ Patrol.Type.Breadcrumb: Breadcrumb :: Text -> Map Text Value -> Maybe EventId -> Maybe Level -> Text -> Maybe UTCTime -> Maybe BreadcrumbType -> Breadcrumb
+ Patrol.Type.Breadcrumb: [category] :: Breadcrumb -> Text
+ Patrol.Type.Breadcrumb: [data_] :: Breadcrumb -> Map Text Value
+ Patrol.Type.Breadcrumb: [eventId] :: Breadcrumb -> Maybe EventId
+ Patrol.Type.Breadcrumb: [level] :: Breadcrumb -> Maybe Level
+ Patrol.Type.Breadcrumb: [message] :: Breadcrumb -> Text
+ Patrol.Type.Breadcrumb: [timestamp] :: Breadcrumb -> Maybe UTCTime
+ Patrol.Type.Breadcrumb: [type_] :: Breadcrumb -> Maybe BreadcrumbType
+ Patrol.Type.Breadcrumb: data Breadcrumb
+ Patrol.Type.Breadcrumb: empty :: Breadcrumb
+ Patrol.Type.Breadcrumb: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.Breadcrumb.Breadcrumb
+ Patrol.Type.Breadcrumb: instance GHC.Classes.Eq Patrol.Type.Breadcrumb.Breadcrumb
+ Patrol.Type.Breadcrumb: instance GHC.Show.Show Patrol.Type.Breadcrumb.Breadcrumb
+ Patrol.Type.BreadcrumbType: Default :: BreadcrumbType
+ Patrol.Type.BreadcrumbType: Http :: BreadcrumbType
+ Patrol.Type.BreadcrumbType: Navigation :: BreadcrumbType
+ Patrol.Type.BreadcrumbType: data BreadcrumbType
+ Patrol.Type.BreadcrumbType: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.BreadcrumbType.BreadcrumbType
+ Patrol.Type.BreadcrumbType: instance GHC.Classes.Eq Patrol.Type.BreadcrumbType.BreadcrumbType
+ Patrol.Type.BreadcrumbType: instance GHC.Show.Show Patrol.Type.BreadcrumbType.BreadcrumbType
+ Patrol.Type.Breadcrumbs: Breadcrumbs :: [Breadcrumb] -> Breadcrumbs
+ Patrol.Type.Breadcrumbs: [values] :: Breadcrumbs -> [Breadcrumb]
+ Patrol.Type.Breadcrumbs: empty :: Breadcrumbs
+ Patrol.Type.Breadcrumbs: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.Breadcrumbs.Breadcrumbs
+ Patrol.Type.Breadcrumbs: instance GHC.Classes.Eq Patrol.Type.Breadcrumbs.Breadcrumbs
+ Patrol.Type.Breadcrumbs: instance GHC.Show.Show Patrol.Type.Breadcrumbs.Breadcrumbs
+ Patrol.Type.Breadcrumbs: newtype Breadcrumbs
+ Patrol.Type.BrowserContext: BrowserContext :: Text -> Text -> BrowserContext
+ Patrol.Type.BrowserContext: [name] :: BrowserContext -> Text
+ Patrol.Type.BrowserContext: [version] :: BrowserContext -> Text
+ Patrol.Type.BrowserContext: data BrowserContext
+ Patrol.Type.BrowserContext: empty :: BrowserContext
+ Patrol.Type.BrowserContext: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.BrowserContext.BrowserContext
+ Patrol.Type.BrowserContext: instance GHC.Classes.Eq Patrol.Type.BrowserContext.BrowserContext
+ Patrol.Type.BrowserContext: instance GHC.Show.Show Patrol.Type.BrowserContext.BrowserContext
+ Patrol.Type.CError: CError :: Text -> Maybe Int -> CError
+ Patrol.Type.CError: [name] :: CError -> Text
+ Patrol.Type.CError: [number] :: CError -> Maybe Int
+ Patrol.Type.CError: data CError
+ Patrol.Type.CError: empty :: CError
+ Patrol.Type.CError: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.CError.CError
+ Patrol.Type.CError: instance GHC.Classes.Eq Patrol.Type.CError.CError
+ Patrol.Type.CError: instance GHC.Show.Show Patrol.Type.CError.CError
+ Patrol.Type.ClientSdkInfo: ClientSdkInfo :: [Text] -> Text -> [ClientSdkPackage] -> Text -> ClientSdkInfo
+ Patrol.Type.ClientSdkInfo: [integrations] :: ClientSdkInfo -> [Text]
+ Patrol.Type.ClientSdkInfo: [name] :: ClientSdkInfo -> Text
+ Patrol.Type.ClientSdkInfo: [packages] :: ClientSdkInfo -> [ClientSdkPackage]
+ Patrol.Type.ClientSdkInfo: [version] :: ClientSdkInfo -> Text
+ Patrol.Type.ClientSdkInfo: data ClientSdkInfo
+ Patrol.Type.ClientSdkInfo: empty :: ClientSdkInfo
+ Patrol.Type.ClientSdkInfo: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.ClientSdkInfo.ClientSdkInfo
+ Patrol.Type.ClientSdkInfo: instance GHC.Classes.Eq Patrol.Type.ClientSdkInfo.ClientSdkInfo
+ Patrol.Type.ClientSdkInfo: instance GHC.Show.Show Patrol.Type.ClientSdkInfo.ClientSdkInfo
+ Patrol.Type.ClientSdkPackage: ClientSdkPackage :: Text -> Text -> ClientSdkPackage
+ Patrol.Type.ClientSdkPackage: [name] :: ClientSdkPackage -> Text
+ Patrol.Type.ClientSdkPackage: [version] :: ClientSdkPackage -> Text
+ Patrol.Type.ClientSdkPackage: data ClientSdkPackage
+ Patrol.Type.ClientSdkPackage: empty :: ClientSdkPackage
+ Patrol.Type.ClientSdkPackage: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.ClientSdkPackage.ClientSdkPackage
+ Patrol.Type.ClientSdkPackage: instance GHC.Classes.Eq Patrol.Type.ClientSdkPackage.ClientSdkPackage
+ Patrol.Type.ClientSdkPackage: instance GHC.Show.Show Patrol.Type.ClientSdkPackage.ClientSdkPackage
+ Patrol.Type.Context: App :: AppContext -> Context
+ Patrol.Type.Context: Browser :: BrowserContext -> Context
+ Patrol.Type.Context: Device :: DeviceContext -> Context
+ Patrol.Type.Context: Gpu :: GpuContext -> Context
+ Patrol.Type.Context: Os :: OsContext -> Context
+ Patrol.Type.Context: Other :: Map Text Value -> Context
+ Patrol.Type.Context: Runtime :: RuntimeContext -> Context
+ Patrol.Type.Context: Trace :: TraceContext -> Context
+ Patrol.Type.Context: data Context
+ Patrol.Type.Context: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.Context.Context
+ Patrol.Type.Context: instance GHC.Classes.Eq Patrol.Type.Context.Context
+ Patrol.Type.Context: instance GHC.Show.Show Patrol.Type.Context.Context
+ Patrol.Type.DebugImage: Apple :: AppleDebugImage -> DebugImage
+ Patrol.Type.DebugImage: Native :: NativeDebugImage -> DebugImage
+ Patrol.Type.DebugImage: Other :: Map Text Value -> DebugImage
+ Patrol.Type.DebugImage: Proguard :: ProguardDebugImage -> DebugImage
+ Patrol.Type.DebugImage: data DebugImage
+ Patrol.Type.DebugImage: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.DebugImage.DebugImage
+ Patrol.Type.DebugImage: instance GHC.Classes.Eq Patrol.Type.DebugImage.DebugImage
+ Patrol.Type.DebugImage: instance GHC.Show.Show Patrol.Type.DebugImage.DebugImage
+ Patrol.Type.DebugMeta: DebugMeta :: [DebugImage] -> Maybe SystemSdkInfo -> DebugMeta
+ Patrol.Type.DebugMeta: [images] :: DebugMeta -> [DebugImage]
+ Patrol.Type.DebugMeta: [sdkInfo] :: DebugMeta -> Maybe SystemSdkInfo
+ Patrol.Type.DebugMeta: data DebugMeta
+ Patrol.Type.DebugMeta: empty :: DebugMeta
+ Patrol.Type.DebugMeta: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.DebugMeta.DebugMeta
+ Patrol.Type.DebugMeta: instance GHC.Classes.Eq Patrol.Type.DebugMeta.DebugMeta
+ Patrol.Type.DebugMeta: instance GHC.Show.Show Patrol.Type.DebugMeta.DebugMeta
+ Patrol.Type.DeviceContext: DeviceContext :: Text -> Maybe Double -> Text -> Maybe UTCTime -> Text -> Maybe Bool -> Text -> Text -> Text -> Maybe Int -> Maybe Int -> Text -> Maybe Int -> Maybe Int -> Maybe Bool -> Text -> Maybe Int -> Text -> Text -> Text -> Maybe Bool -> Text -> Maybe Int -> Maybe Double -> Maybe Double -> Maybe Double -> Text -> Maybe Bool -> Maybe Int -> Maybe Bool -> Maybe Bool -> Maybe Bool -> Maybe Bool -> Maybe Bool -> Text -> Maybe Int -> DeviceContext
+ Patrol.Type.DeviceContext: [arch] :: DeviceContext -> Text
+ Patrol.Type.DeviceContext: [batteryLevel] :: DeviceContext -> Maybe Double
+ Patrol.Type.DeviceContext: [batteryStatus] :: DeviceContext -> Text
+ Patrol.Type.DeviceContext: [bootTime] :: DeviceContext -> Maybe UTCTime
+ Patrol.Type.DeviceContext: [brand] :: DeviceContext -> Text
+ Patrol.Type.DeviceContext: [charging] :: DeviceContext -> Maybe Bool
+ Patrol.Type.DeviceContext: [cpuDescription] :: DeviceContext -> Text
+ Patrol.Type.DeviceContext: [deviceType] :: DeviceContext -> Text
+ Patrol.Type.DeviceContext: [deviceUniqueIdentifier] :: DeviceContext -> Text
+ Patrol.Type.DeviceContext: [externalFreeStorage] :: DeviceContext -> Maybe Int
+ Patrol.Type.DeviceContext: [externalStorageSize] :: DeviceContext -> Maybe Int
+ Patrol.Type.DeviceContext: [family] :: DeviceContext -> Text
+ Patrol.Type.DeviceContext: [freeMemory] :: DeviceContext -> Maybe Int
+ Patrol.Type.DeviceContext: [freeStorage] :: DeviceContext -> Maybe Int
+ Patrol.Type.DeviceContext: [lowMemory] :: DeviceContext -> Maybe Bool
+ Patrol.Type.DeviceContext: [manufacturer] :: DeviceContext -> Text
+ Patrol.Type.DeviceContext: [memorySize] :: DeviceContext -> Maybe Int
+ Patrol.Type.DeviceContext: [modelId] :: DeviceContext -> Text
+ Patrol.Type.DeviceContext: [model] :: DeviceContext -> Text
+ Patrol.Type.DeviceContext: [name] :: DeviceContext -> Text
+ Patrol.Type.DeviceContext: [online] :: DeviceContext -> Maybe Bool
+ Patrol.Type.DeviceContext: [orientation] :: DeviceContext -> Text
+ Patrol.Type.DeviceContext: [processorCount] :: DeviceContext -> Maybe Int
+ Patrol.Type.DeviceContext: [processorFrequency] :: DeviceContext -> Maybe Double
+ Patrol.Type.DeviceContext: [screenDensity] :: DeviceContext -> Maybe Double
+ Patrol.Type.DeviceContext: [screenDpi] :: DeviceContext -> Maybe Double
+ Patrol.Type.DeviceContext: [screenResolution] :: DeviceContext -> Text
+ Patrol.Type.DeviceContext: [simulator] :: DeviceContext -> Maybe Bool
+ Patrol.Type.DeviceContext: [storageSize] :: DeviceContext -> Maybe Int
+ Patrol.Type.DeviceContext: [supportsAccelerometer] :: DeviceContext -> Maybe Bool
+ Patrol.Type.DeviceContext: [supportsAudio] :: DeviceContext -> Maybe Bool
+ Patrol.Type.DeviceContext: [supportsGyroscope] :: DeviceContext -> Maybe Bool
+ Patrol.Type.DeviceContext: [supportsLocationService] :: DeviceContext -> Maybe Bool
+ Patrol.Type.DeviceContext: [supportsVibration] :: DeviceContext -> Maybe Bool
+ Patrol.Type.DeviceContext: [timezone] :: DeviceContext -> Text
+ Patrol.Type.DeviceContext: [usableMemory] :: DeviceContext -> Maybe Int
+ Patrol.Type.DeviceContext: data DeviceContext
+ Patrol.Type.DeviceContext: empty :: DeviceContext
+ Patrol.Type.DeviceContext: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.DeviceContext.DeviceContext
+ Patrol.Type.DeviceContext: instance GHC.Classes.Eq Patrol.Type.DeviceContext.DeviceContext
+ Patrol.Type.DeviceContext: instance GHC.Show.Show Patrol.Type.DeviceContext.DeviceContext
+ Patrol.Type.Dsn: intoAuthorization :: Dsn -> ByteString
+ Patrol.Type.Dsn: intoUri :: Dsn -> URI
+ Patrol.Type.ErrorType: ClockDrift :: ErrorType
+ Patrol.Type.ErrorType: FetchGenericError :: ErrorType
+ Patrol.Type.ErrorType: FetchInvalidEncoding :: ErrorType
+ Patrol.Type.ErrorType: FetchInvalidHttpCode :: ErrorType
+ Patrol.Type.ErrorType: FetchTimeout :: ErrorType
+ Patrol.Type.ErrorType: FetchTooLarge :: ErrorType
+ Patrol.Type.ErrorType: FutureTimestamp :: ErrorType
+ Patrol.Type.ErrorType: InvalidAttribute :: ErrorType
+ Patrol.Type.ErrorType: InvalidData :: ErrorType
+ Patrol.Type.ErrorType: InvalidEnvironment :: ErrorType
+ Patrol.Type.ErrorType: JsFetchTimeout :: ErrorType
+ Patrol.Type.ErrorType: JsGenericFetchError :: ErrorType
+ Patrol.Type.ErrorType: JsInvalidContent :: ErrorType
+ Patrol.Type.ErrorType: JsInvalidHttpCode :: ErrorType
+ Patrol.Type.ErrorType: JsInvalidSourceEncoding :: ErrorType
+ Patrol.Type.ErrorType: JsInvalidSourcemap :: ErrorType
+ Patrol.Type.ErrorType: JsInvalidSourcemapLocation :: ErrorType
+ Patrol.Type.ErrorType: JsMissingSource :: ErrorType
+ Patrol.Type.ErrorType: JsNoColumn :: ErrorType
+ Patrol.Type.ErrorType: JsTooLarge :: ErrorType
+ Patrol.Type.ErrorType: JsTooManyRemoteSources :: ErrorType
+ Patrol.Type.ErrorType: MissingAttribute :: ErrorType
+ Patrol.Type.ErrorType: NativeBadDsym :: ErrorType
+ Patrol.Type.ErrorType: NativeInternalFailure :: ErrorType
+ Patrol.Type.ErrorType: NativeMissingDsym :: ErrorType
+ Patrol.Type.ErrorType: NativeMissingOptionallyBundledDsym :: ErrorType
+ Patrol.Type.ErrorType: NativeMissingSymbol :: ErrorType
+ Patrol.Type.ErrorType: NativeMissingSystemDsym :: ErrorType
+ Patrol.Type.ErrorType: NativeNoCrashedThread :: ErrorType
+ Patrol.Type.ErrorType: NativeSimulatorFrame :: ErrorType
+ Patrol.Type.ErrorType: NativeSymbolicatorFailed :: ErrorType
+ Patrol.Type.ErrorType: NativeUnknownImage :: ErrorType
+ Patrol.Type.ErrorType: PastTimestamp :: ErrorType
+ Patrol.Type.ErrorType: ProguardMissingLineno :: ErrorType
+ Patrol.Type.ErrorType: ProguardMissingMapping :: ErrorType
+ Patrol.Type.ErrorType: RestrictedIp :: ErrorType
+ Patrol.Type.ErrorType: SecurityViolation :: ErrorType
+ Patrol.Type.ErrorType: TooLargeForCache :: ErrorType
+ Patrol.Type.ErrorType: UnknownError :: ErrorType
+ Patrol.Type.ErrorType: ValueTooLong :: ErrorType
+ Patrol.Type.ErrorType: data ErrorType
+ Patrol.Type.ErrorType: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.ErrorType.ErrorType
+ Patrol.Type.ErrorType: instance GHC.Classes.Eq Patrol.Type.ErrorType.ErrorType
+ Patrol.Type.ErrorType: instance GHC.Show.Show Patrol.Type.ErrorType.ErrorType
+ Patrol.Type.Event: [breadcrumbs] :: Event -> Maybe Breadcrumbs
+ Patrol.Type.Event: [contexts] :: Event -> Map Text Context
+ Patrol.Type.Event: [debugMeta] :: Event -> Maybe DebugMeta
+ Patrol.Type.Event: [errors] :: Event -> [EventProcessingError]
+ Patrol.Type.Event: [logentry] :: Event -> Maybe LogEntry
+ Patrol.Type.Event: [sdk] :: Event -> Maybe ClientSdkInfo
+ Patrol.Type.Event: [threads] :: Event -> Maybe Threads
+ Patrol.Type.Event: [timeSpent] :: Event -> Maybe NominalDiffTime
+ Patrol.Type.Event: [transactionInfo] :: Event -> Maybe TransactionInfo
+ Patrol.Type.Event: [type_] :: Event -> Maybe EventType
+ Patrol.Type.Event: [version] :: Event -> Text
+ Patrol.Type.Event: empty :: Event
+ Patrol.Type.Event: intoRequest :: MonadThrow m => Dsn -> Event -> m Request
+ Patrol.Type.EventId: EventId :: UUID -> EventId
+ Patrol.Type.EventId: empty :: EventId
+ Patrol.Type.EventId: fromText :: MonadThrow m => Text -> m EventId
+ Patrol.Type.EventId: intoText :: EventId -> Text
+ Patrol.Type.EventId: intoUuid :: EventId -> UUID
+ Patrol.Type.EventId: newtype EventId
+ Patrol.Type.EventId: random :: MonadIO io => io EventId
+ Patrol.Type.EventProcessingError: EventProcessingError :: Text -> ErrorType -> Value -> EventProcessingError
+ Patrol.Type.EventProcessingError: [name] :: EventProcessingError -> Text
+ Patrol.Type.EventProcessingError: [type_] :: EventProcessingError -> ErrorType
+ Patrol.Type.EventProcessingError: [value] :: EventProcessingError -> Value
+ Patrol.Type.EventProcessingError: data EventProcessingError
+ Patrol.Type.EventProcessingError: empty :: EventProcessingError
+ Patrol.Type.EventProcessingError: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.EventProcessingError.EventProcessingError
+ Patrol.Type.EventProcessingError: instance GHC.Classes.Eq Patrol.Type.EventProcessingError.EventProcessingError
+ Patrol.Type.EventProcessingError: instance GHC.Show.Show Patrol.Type.EventProcessingError.EventProcessingError
+ Patrol.Type.EventType: Csp :: EventType
+ Patrol.Type.EventType: Default :: EventType
+ Patrol.Type.EventType: Error :: EventType
+ Patrol.Type.EventType: Expectct :: EventType
+ Patrol.Type.EventType: Expectstaple :: EventType
+ Patrol.Type.EventType: Hpkp :: EventType
+ Patrol.Type.EventType: Transaction :: EventType
+ Patrol.Type.EventType: data EventType
+ Patrol.Type.EventType: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.EventType.EventType
+ Patrol.Type.EventType: instance GHC.Classes.Eq Patrol.Type.EventType.EventType
+ Patrol.Type.EventType: instance GHC.Show.Show Patrol.Type.EventType.EventType
+ Patrol.Type.Exception: [mechanism] :: Exception -> Maybe Mechanism
+ Patrol.Type.Exception: [stacktrace] :: Exception -> Maybe Stacktrace
+ Patrol.Type.Exception: [threadId] :: Exception -> Text
+ Patrol.Type.Exception: empty :: Exception
+ Patrol.Type.Exceptions: Exceptions :: [Exception] -> Exceptions
+ Patrol.Type.Exceptions: [values] :: Exceptions -> [Exception]
+ Patrol.Type.Exceptions: empty :: Exceptions
+ Patrol.Type.Exceptions: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.Exceptions.Exceptions
+ Patrol.Type.Exceptions: instance GHC.Classes.Eq Patrol.Type.Exceptions.Exceptions
+ Patrol.Type.Exceptions: instance GHC.Show.Show Patrol.Type.Exceptions.Exceptions
+ Patrol.Type.Exceptions: newtype Exceptions
+ Patrol.Type.Frame: [absPath] :: Frame -> Text
+ Patrol.Type.Frame: [addrMode] :: Frame -> Text
+ Patrol.Type.Frame: [contextLine] :: Frame -> Text
+ Patrol.Type.Frame: [imageAddr] :: Frame -> Text
+ Patrol.Type.Frame: [inApp] :: Frame -> Maybe Bool
+ Patrol.Type.Frame: [instructionAddr] :: Frame -> Text
+ Patrol.Type.Frame: [platform] :: Frame -> Maybe Platform
+ Patrol.Type.Frame: [postContext] :: Frame -> [Text]
+ Patrol.Type.Frame: [preContext] :: Frame -> [Text]
+ Patrol.Type.Frame: [rawFunction] :: Frame -> Text
+ Patrol.Type.Frame: [stackStart] :: Frame -> Maybe Bool
+ Patrol.Type.Frame: [symbolAddr] :: Frame -> Text
+ Patrol.Type.Frame: [vars] :: Frame -> Map Text Value
+ Patrol.Type.Frame: empty :: Frame
+ Patrol.Type.Geo: Geo :: Text -> Text -> Text -> Geo
+ Patrol.Type.Geo: [city] :: Geo -> Text
+ Patrol.Type.Geo: [countryCode] :: Geo -> Text
+ Patrol.Type.Geo: [region] :: Geo -> Text
+ Patrol.Type.Geo: data Geo
+ Patrol.Type.Geo: empty :: Geo
+ Patrol.Type.Geo: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.Geo.Geo
+ Patrol.Type.Geo: instance GHC.Classes.Eq Patrol.Type.Geo.Geo
+ Patrol.Type.Geo: instance GHC.Show.Show Patrol.Type.Geo.Geo
+ Patrol.Type.GpuContext: GpuContext :: Text -> Text -> Value -> Maybe Int -> Maybe Double -> Maybe Bool -> Text -> Text -> Maybe Bool -> Maybe Bool -> Maybe Bool -> Text -> Text -> Text -> GpuContext
+ Patrol.Type.GpuContext: [apiType] :: GpuContext -> Text
+ Patrol.Type.GpuContext: [graphicsShaderLevel] :: GpuContext -> Text
+ Patrol.Type.GpuContext: [id] :: GpuContext -> Value
+ Patrol.Type.GpuContext: [maxTextureSize] :: GpuContext -> Maybe Int
+ Patrol.Type.GpuContext: [memorySize] :: GpuContext -> Maybe Double
+ Patrol.Type.GpuContext: [multiThreadedRendering] :: GpuContext -> Maybe Bool
+ Patrol.Type.GpuContext: [name] :: GpuContext -> Text
+ Patrol.Type.GpuContext: [npotSupport] :: GpuContext -> Text
+ Patrol.Type.GpuContext: [supportsComputeShaders] :: GpuContext -> Maybe Bool
+ Patrol.Type.GpuContext: [supportsGeometryShaders] :: GpuContext -> Maybe Bool
+ Patrol.Type.GpuContext: [supportsRayTracing] :: GpuContext -> Maybe Bool
+ Patrol.Type.GpuContext: [vendorId] :: GpuContext -> Text
+ Patrol.Type.GpuContext: [vendorName] :: GpuContext -> Text
+ Patrol.Type.GpuContext: [version] :: GpuContext -> Text
+ Patrol.Type.GpuContext: data GpuContext
+ Patrol.Type.GpuContext: empty :: GpuContext
+ Patrol.Type.GpuContext: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.GpuContext.GpuContext
+ Patrol.Type.GpuContext: instance GHC.Classes.Eq Patrol.Type.GpuContext.GpuContext
+ Patrol.Type.GpuContext: instance GHC.Show.Show Patrol.Type.GpuContext.GpuContext
+ Patrol.Type.LogEntry: LogEntry :: Text -> Text -> Value -> LogEntry
+ Patrol.Type.LogEntry: [formatted] :: LogEntry -> Text
+ Patrol.Type.LogEntry: [message] :: LogEntry -> Text
+ Patrol.Type.LogEntry: [params] :: LogEntry -> Value
+ Patrol.Type.LogEntry: data LogEntry
+ Patrol.Type.LogEntry: empty :: LogEntry
+ Patrol.Type.LogEntry: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.LogEntry.LogEntry
+ Patrol.Type.LogEntry: instance GHC.Classes.Eq Patrol.Type.LogEntry.LogEntry
+ Patrol.Type.LogEntry: instance GHC.Show.Show Patrol.Type.LogEntry.LogEntry
+ Patrol.Type.MachException: MachException :: Maybe Int -> Maybe Int -> Text -> Maybe Int -> MachException
+ Patrol.Type.MachException: [code] :: MachException -> Maybe Int
+ Patrol.Type.MachException: [exception] :: MachException -> Maybe Int
+ Patrol.Type.MachException: [name] :: MachException -> Text
+ Patrol.Type.MachException: [subcode] :: MachException -> Maybe Int
+ Patrol.Type.MachException: data MachException
+ Patrol.Type.MachException: empty :: MachException
+ Patrol.Type.MachException: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.MachException.MachException
+ Patrol.Type.MachException: instance GHC.Classes.Eq Patrol.Type.MachException.MachException
+ Patrol.Type.MachException: instance GHC.Show.Show Patrol.Type.MachException.MachException
+ Patrol.Type.Mechanism: Mechanism :: Map Text Value -> Text -> Maybe Bool -> Text -> Maybe MechanismMeta -> Maybe Bool -> Text -> Mechanism
+ Patrol.Type.Mechanism: [data_] :: Mechanism -> Map Text Value
+ Patrol.Type.Mechanism: [description] :: Mechanism -> Text
+ Patrol.Type.Mechanism: [handled] :: Mechanism -> Maybe Bool
+ Patrol.Type.Mechanism: [helpLink] :: Mechanism -> Text
+ Patrol.Type.Mechanism: [meta] :: Mechanism -> Maybe MechanismMeta
+ Patrol.Type.Mechanism: [synthetic] :: Mechanism -> Maybe Bool
+ Patrol.Type.Mechanism: [type_] :: Mechanism -> Text
+ Patrol.Type.Mechanism: data Mechanism
+ Patrol.Type.Mechanism: empty :: Mechanism
+ Patrol.Type.Mechanism: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.Mechanism.Mechanism
+ Patrol.Type.Mechanism: instance GHC.Classes.Eq Patrol.Type.Mechanism.Mechanism
+ Patrol.Type.Mechanism: instance GHC.Show.Show Patrol.Type.Mechanism.Mechanism
+ Patrol.Type.MechanismMeta: MechanismMeta :: Maybe CError -> Maybe MachException -> Maybe NsError -> Maybe PosixSignal -> MechanismMeta
+ Patrol.Type.MechanismMeta: [errno] :: MechanismMeta -> Maybe CError
+ Patrol.Type.MechanismMeta: [machException] :: MechanismMeta -> Maybe MachException
+ Patrol.Type.MechanismMeta: [nsError] :: MechanismMeta -> Maybe NsError
+ Patrol.Type.MechanismMeta: [signal] :: MechanismMeta -> Maybe PosixSignal
+ Patrol.Type.MechanismMeta: data MechanismMeta
+ Patrol.Type.MechanismMeta: empty :: MechanismMeta
+ Patrol.Type.MechanismMeta: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.MechanismMeta.MechanismMeta
+ Patrol.Type.MechanismMeta: instance GHC.Classes.Eq Patrol.Type.MechanismMeta.MechanismMeta
+ Patrol.Type.MechanismMeta: instance GHC.Show.Show Patrol.Type.MechanismMeta.MechanismMeta
+ Patrol.Type.NativeDebugImage: NativeDebugImage :: Text -> Text -> Text -> Text -> Text -> Text -> Maybe Int -> Text -> Text -> NativeDebugImage
+ Patrol.Type.NativeDebugImage: [arch] :: NativeDebugImage -> Text
+ Patrol.Type.NativeDebugImage: [codeFile] :: NativeDebugImage -> Text
+ Patrol.Type.NativeDebugImage: [codeId] :: NativeDebugImage -> Text
+ Patrol.Type.NativeDebugImage: [debugFile] :: NativeDebugImage -> Text
+ Patrol.Type.NativeDebugImage: [debugId] :: NativeDebugImage -> Text
+ Patrol.Type.NativeDebugImage: [imageAddr] :: NativeDebugImage -> Text
+ Patrol.Type.NativeDebugImage: [imageSize] :: NativeDebugImage -> Maybe Int
+ Patrol.Type.NativeDebugImage: [imageVmaddr] :: NativeDebugImage -> Text
+ Patrol.Type.NativeDebugImage: [type_] :: NativeDebugImage -> Text
+ Patrol.Type.NativeDebugImage: data NativeDebugImage
+ Patrol.Type.NativeDebugImage: empty :: NativeDebugImage
+ Patrol.Type.NativeDebugImage: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.NativeDebugImage.NativeDebugImage
+ Patrol.Type.NativeDebugImage: instance GHC.Classes.Eq Patrol.Type.NativeDebugImage.NativeDebugImage
+ Patrol.Type.NativeDebugImage: instance GHC.Show.Show Patrol.Type.NativeDebugImage.NativeDebugImage
+ Patrol.Type.NsError: NsError :: Maybe Int -> Text -> NsError
+ Patrol.Type.NsError: [code] :: NsError -> Maybe Int
+ Patrol.Type.NsError: [domain] :: NsError -> Text
+ Patrol.Type.NsError: data NsError
+ Patrol.Type.NsError: empty :: NsError
+ Patrol.Type.NsError: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.NsError.NsError
+ Patrol.Type.NsError: instance GHC.Classes.Eq Patrol.Type.NsError.NsError
+ Patrol.Type.NsError: instance GHC.Show.Show Patrol.Type.NsError.NsError
+ Patrol.Type.OsContext: OsContext :: Text -> Text -> Text -> Text -> Maybe Bool -> Text -> OsContext
+ Patrol.Type.OsContext: [build] :: OsContext -> Text
+ Patrol.Type.OsContext: [kernelVersion] :: OsContext -> Text
+ Patrol.Type.OsContext: [name] :: OsContext -> Text
+ Patrol.Type.OsContext: [rawDescription] :: OsContext -> Text
+ Patrol.Type.OsContext: [rooted] :: OsContext -> Maybe Bool
+ Patrol.Type.OsContext: [version] :: OsContext -> Text
+ Patrol.Type.OsContext: data OsContext
+ Patrol.Type.OsContext: empty :: OsContext
+ Patrol.Type.OsContext: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.OsContext.OsContext
+ Patrol.Type.OsContext: instance GHC.Classes.Eq Patrol.Type.OsContext.OsContext
+ Patrol.Type.OsContext: instance GHC.Show.Show Patrol.Type.OsContext.OsContext
+ Patrol.Type.PosixSignal: PosixSignal :: Maybe Int -> Text -> Text -> Maybe Int -> PosixSignal
+ Patrol.Type.PosixSignal: [codeName] :: PosixSignal -> Text
+ Patrol.Type.PosixSignal: [code] :: PosixSignal -> Maybe Int
+ Patrol.Type.PosixSignal: [name] :: PosixSignal -> Text
+ Patrol.Type.PosixSignal: [number] :: PosixSignal -> Maybe Int
+ Patrol.Type.PosixSignal: data PosixSignal
+ Patrol.Type.PosixSignal: empty :: PosixSignal
+ Patrol.Type.PosixSignal: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.PosixSignal.PosixSignal
+ Patrol.Type.PosixSignal: instance GHC.Classes.Eq Patrol.Type.PosixSignal.PosixSignal
+ Patrol.Type.PosixSignal: instance GHC.Show.Show Patrol.Type.PosixSignal.PosixSignal
+ Patrol.Type.ProguardDebugImage: ProguardDebugImage :: Text -> ProguardDebugImage
+ Patrol.Type.ProguardDebugImage: [uuid] :: ProguardDebugImage -> Text
+ Patrol.Type.ProguardDebugImage: empty :: ProguardDebugImage
+ Patrol.Type.ProguardDebugImage: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.ProguardDebugImage.ProguardDebugImage
+ Patrol.Type.ProguardDebugImage: instance GHC.Classes.Eq Patrol.Type.ProguardDebugImage.ProguardDebugImage
+ Patrol.Type.ProguardDebugImage: instance GHC.Show.Show Patrol.Type.ProguardDebugImage.ProguardDebugImage
+ Patrol.Type.ProguardDebugImage: newtype ProguardDebugImage
+ Patrol.Type.Request: [fragment] :: Request -> Text
+ Patrol.Type.Request: [inferredContentType] :: Request -> Text
+ Patrol.Type.Request: empty :: Request
+ Patrol.Type.Response: [id] :: Response -> EventId
+ Patrol.Type.RuntimeContext: RuntimeContext :: Text -> Text -> Text -> Text -> RuntimeContext
+ Patrol.Type.RuntimeContext: [build] :: RuntimeContext -> Text
+ Patrol.Type.RuntimeContext: [name] :: RuntimeContext -> Text
+ Patrol.Type.RuntimeContext: [rawDescription] :: RuntimeContext -> Text
+ Patrol.Type.RuntimeContext: [version] :: RuntimeContext -> Text
+ Patrol.Type.RuntimeContext: data RuntimeContext
+ Patrol.Type.RuntimeContext: empty :: RuntimeContext
+ Patrol.Type.RuntimeContext: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.RuntimeContext.RuntimeContext
+ Patrol.Type.RuntimeContext: instance GHC.Classes.Eq Patrol.Type.RuntimeContext.RuntimeContext
+ Patrol.Type.RuntimeContext: instance GHC.Show.Show Patrol.Type.RuntimeContext.RuntimeContext
+ Patrol.Type.SpanStatus: Aborted :: SpanStatus
+ Patrol.Type.SpanStatus: AlreadyExists :: SpanStatus
+ Patrol.Type.SpanStatus: Cancelled :: SpanStatus
+ Patrol.Type.SpanStatus: DataLoss :: SpanStatus
+ Patrol.Type.SpanStatus: DeadlineExceeded :: SpanStatus
+ Patrol.Type.SpanStatus: FailedPrecondition :: SpanStatus
+ Patrol.Type.SpanStatus: InternalError :: SpanStatus
+ Patrol.Type.SpanStatus: InvalidArgument :: SpanStatus
+ Patrol.Type.SpanStatus: NotFound :: SpanStatus
+ Patrol.Type.SpanStatus: Ok :: SpanStatus
+ Patrol.Type.SpanStatus: OutOfRange :: SpanStatus
+ Patrol.Type.SpanStatus: PermissionDenied :: SpanStatus
+ Patrol.Type.SpanStatus: ResourceExhausted :: SpanStatus
+ Patrol.Type.SpanStatus: Unauthenticated :: SpanStatus
+ Patrol.Type.SpanStatus: Unavailable :: SpanStatus
+ Patrol.Type.SpanStatus: Unimplemented :: SpanStatus
+ Patrol.Type.SpanStatus: Unknown :: SpanStatus
+ Patrol.Type.SpanStatus: data SpanStatus
+ Patrol.Type.SpanStatus: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.SpanStatus.SpanStatus
+ Patrol.Type.SpanStatus: instance GHC.Classes.Eq Patrol.Type.SpanStatus.SpanStatus
+ Patrol.Type.SpanStatus: instance GHC.Show.Show Patrol.Type.SpanStatus.SpanStatus
+ Patrol.Type.Stacktrace: Stacktrace :: [Frame] -> Map Text Text -> Stacktrace
+ Patrol.Type.Stacktrace: [frames] :: Stacktrace -> [Frame]
+ Patrol.Type.Stacktrace: [registers] :: Stacktrace -> Map Text Text
+ Patrol.Type.Stacktrace: data Stacktrace
+ Patrol.Type.Stacktrace: empty :: Stacktrace
+ Patrol.Type.Stacktrace: fromCallStack :: CallStack -> Stacktrace
+ Patrol.Type.Stacktrace: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.Stacktrace.Stacktrace
+ Patrol.Type.Stacktrace: instance GHC.Classes.Eq Patrol.Type.Stacktrace.Stacktrace
+ Patrol.Type.Stacktrace: instance GHC.Show.Show Patrol.Type.Stacktrace.Stacktrace
+ Patrol.Type.SystemSdkInfo: SystemSdkInfo :: Text -> Maybe Int -> Maybe Int -> Maybe Int -> SystemSdkInfo
+ Patrol.Type.SystemSdkInfo: [sdkName] :: SystemSdkInfo -> Text
+ Patrol.Type.SystemSdkInfo: [versionMajor] :: SystemSdkInfo -> Maybe Int
+ Patrol.Type.SystemSdkInfo: [versionMinor] :: SystemSdkInfo -> Maybe Int
+ Patrol.Type.SystemSdkInfo: [versionPatchlevel] :: SystemSdkInfo -> Maybe Int
+ Patrol.Type.SystemSdkInfo: data SystemSdkInfo
+ Patrol.Type.SystemSdkInfo: empty :: SystemSdkInfo
+ Patrol.Type.SystemSdkInfo: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.SystemSdkInfo.SystemSdkInfo
+ Patrol.Type.SystemSdkInfo: instance GHC.Classes.Eq Patrol.Type.SystemSdkInfo.SystemSdkInfo
+ Patrol.Type.SystemSdkInfo: instance GHC.Show.Show Patrol.Type.SystemSdkInfo.SystemSdkInfo
+ Patrol.Type.Thread: Thread :: Maybe Bool -> Maybe Bool -> Text -> Text -> Maybe Stacktrace -> Thread
+ Patrol.Type.Thread: [crashed] :: Thread -> Maybe Bool
+ Patrol.Type.Thread: [current] :: Thread -> Maybe Bool
+ Patrol.Type.Thread: [id] :: Thread -> Text
+ Patrol.Type.Thread: [name] :: Thread -> Text
+ Patrol.Type.Thread: [stacktrace] :: Thread -> Maybe Stacktrace
+ Patrol.Type.Thread: data Thread
+ Patrol.Type.Thread: empty :: Thread
+ Patrol.Type.Thread: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.Thread.Thread
+ Patrol.Type.Thread: instance GHC.Classes.Eq Patrol.Type.Thread.Thread
+ Patrol.Type.Thread: instance GHC.Show.Show Patrol.Type.Thread.Thread
+ Patrol.Type.Threads: Threads :: [Thread] -> Threads
+ Patrol.Type.Threads: [values] :: Threads -> [Thread]
+ Patrol.Type.Threads: empty :: Threads
+ Patrol.Type.Threads: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.Threads.Threads
+ Patrol.Type.Threads: instance GHC.Classes.Eq Patrol.Type.Threads.Threads
+ Patrol.Type.Threads: instance GHC.Show.Show Patrol.Type.Threads.Threads
+ Patrol.Type.Threads: newtype Threads
+ Patrol.Type.TraceContext: TraceContext :: Maybe Int -> Text -> Text -> Text -> Maybe SpanStatus -> Text -> TraceContext
+ Patrol.Type.TraceContext: [exclusiveTime] :: TraceContext -> Maybe Int
+ Patrol.Type.TraceContext: [op] :: TraceContext -> Text
+ Patrol.Type.TraceContext: [parentSpanId] :: TraceContext -> Text
+ Patrol.Type.TraceContext: [spanId] :: TraceContext -> Text
+ Patrol.Type.TraceContext: [status] :: TraceContext -> Maybe SpanStatus
+ Patrol.Type.TraceContext: [traceId] :: TraceContext -> Text
+ Patrol.Type.TraceContext: data TraceContext
+ Patrol.Type.TraceContext: empty :: TraceContext
+ Patrol.Type.TraceContext: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.TraceContext.TraceContext
+ Patrol.Type.TraceContext: instance GHC.Classes.Eq Patrol.Type.TraceContext.TraceContext
+ Patrol.Type.TraceContext: instance GHC.Show.Show Patrol.Type.TraceContext.TraceContext
+ Patrol.Type.TransactionInfo: TransactionInfo :: Text -> Maybe TransactionSource -> TransactionInfo
+ Patrol.Type.TransactionInfo: [original] :: TransactionInfo -> Text
+ Patrol.Type.TransactionInfo: [source] :: TransactionInfo -> Maybe TransactionSource
+ Patrol.Type.TransactionInfo: data TransactionInfo
+ Patrol.Type.TransactionInfo: empty :: TransactionInfo
+ Patrol.Type.TransactionInfo: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.TransactionInfo.TransactionInfo
+ Patrol.Type.TransactionInfo: instance GHC.Classes.Eq Patrol.Type.TransactionInfo.TransactionInfo
+ Patrol.Type.TransactionInfo: instance GHC.Show.Show Patrol.Type.TransactionInfo.TransactionInfo
+ Patrol.Type.TransactionSource: Component :: TransactionSource
+ Patrol.Type.TransactionSource: Custom :: TransactionSource
+ Patrol.Type.TransactionSource: Route :: TransactionSource
+ Patrol.Type.TransactionSource: Task :: TransactionSource
+ Patrol.Type.TransactionSource: Unknown :: TransactionSource
+ Patrol.Type.TransactionSource: Url :: TransactionSource
+ Patrol.Type.TransactionSource: View :: TransactionSource
+ Patrol.Type.TransactionSource: data TransactionSource
+ Patrol.Type.TransactionSource: instance Data.Aeson.Types.ToJSON.ToJSON Patrol.Type.TransactionSource.TransactionSource
+ Patrol.Type.TransactionSource: instance GHC.Classes.Eq Patrol.Type.TransactionSource.TransactionSource
+ Patrol.Type.TransactionSource: instance GHC.Show.Show Patrol.Type.TransactionSource.TransactionSource
+ Patrol.Type.User: [data_] :: User -> Map Text Value
+ Patrol.Type.User: [geo] :: User -> Maybe Geo
+ Patrol.Type.User: [id] :: User -> Text
+ Patrol.Type.User: [name] :: User -> Text
+ Patrol.Type.User: [segment] :: User -> Text
+ Patrol.Type.User: empty :: User
+ Patrol.Version: string :: String
+ Patrol.Version: text :: Text
+ Patrol.Version: version :: Version
- Patrol.Client: store :: Manager -> Dsn -> Event -> IO EventId
+ Patrol.Client: store :: (MonadIO io, MonadThrow io) => Manager -> Dsn -> Event -> io Response
- Patrol.Type.Dsn: Dsn :: Text -> Text -> Maybe Text -> Text -> Maybe Text -> Text -> Text -> Dsn
+ Patrol.Type.Dsn: Dsn :: Text -> Text -> Text -> Text -> Maybe Natural -> Text -> Text -> Dsn
- Patrol.Type.Dsn: [port] :: Dsn -> Maybe Text
+ Patrol.Type.Dsn: [port] :: Dsn -> Maybe Natural
- Patrol.Type.Dsn: [secretKey] :: Dsn -> Maybe Text
+ Patrol.Type.Dsn: [secretKey] :: Dsn -> Text
- Patrol.Type.Dsn: fromUri :: URI -> Either String Dsn
+ Patrol.Type.Dsn: fromUri :: MonadThrow m => URI -> m Dsn
- Patrol.Type.Event: Event :: Maybe Text -> Maybe Text -> EventId -> Maybe [Exception] -> Maybe Object -> Maybe [Text] -> Maybe Level -> Maybe Text -> Maybe (Map Text Text) -> Platform -> Maybe Text -> Maybe Request -> Maybe Text -> Maybe (Map Text Text) -> Timestamp -> Maybe Text -> Maybe User -> Event
+ Patrol.Type.Event: Event :: Maybe Breadcrumbs -> Map Text Context -> Maybe DebugMeta -> Text -> Text -> [EventProcessingError] -> EventId -> Maybe Exceptions -> Map Text Value -> [Text] -> Maybe Level -> Maybe LogEntry -> Text -> Map Text Text -> Maybe Platform -> Text -> Maybe Request -> Maybe ClientSdkInfo -> Text -> Map Text Text -> Maybe Threads -> Maybe NominalDiffTime -> Maybe UTCTime -> Text -> Maybe TransactionInfo -> Maybe EventType -> Maybe User -> Text -> Event
- Patrol.Type.Event: [dist] :: Event -> Maybe Text
+ Patrol.Type.Event: [dist] :: Event -> Text
- Patrol.Type.Event: [environment] :: Event -> Maybe Text
+ Patrol.Type.Event: [environment] :: Event -> Text
- Patrol.Type.Event: [exception] :: Event -> Maybe [Exception]
+ Patrol.Type.Event: [exception] :: Event -> Maybe Exceptions
- Patrol.Type.Event: [extra] :: Event -> Maybe Object
+ Patrol.Type.Event: [extra] :: Event -> Map Text Value
- Patrol.Type.Event: [fingerprint] :: Event -> Maybe [Text]
+ Patrol.Type.Event: [fingerprint] :: Event -> [Text]
- Patrol.Type.Event: [logger] :: Event -> Maybe Text
+ Patrol.Type.Event: [logger] :: Event -> Text
- Patrol.Type.Event: [modules] :: Event -> Maybe (Map Text Text)
+ Patrol.Type.Event: [modules] :: Event -> Map Text Text
- Patrol.Type.Event: [platform] :: Event -> Platform
+ Patrol.Type.Event: [platform] :: Event -> Maybe Platform
- Patrol.Type.Event: [release] :: Event -> Maybe Text
+ Patrol.Type.Event: [release] :: Event -> Text
- Patrol.Type.Event: [serverName] :: Event -> Maybe Text
+ Patrol.Type.Event: [serverName] :: Event -> Text
- Patrol.Type.Event: [tags] :: Event -> Maybe (Map Text Text)
+ Patrol.Type.Event: [tags] :: Event -> Map Text Text
- Patrol.Type.Event: [timestamp] :: Event -> Timestamp
+ Patrol.Type.Event: [timestamp] :: Event -> Maybe UTCTime
- Patrol.Type.Event: [transaction] :: Event -> Maybe Text
+ Patrol.Type.Event: [transaction] :: Event -> Text
- Patrol.Type.Exception: Exception :: Maybe Text -> Maybe StackTrace -> Text -> Text -> Exception
+ Patrol.Type.Exception: Exception :: Maybe Mechanism -> Text -> Maybe Stacktrace -> Text -> Text -> Text -> Exception
- Patrol.Type.Exception: [module_] :: Exception -> Maybe Text
+ Patrol.Type.Exception: [module_] :: Exception -> Text
- Patrol.Type.Frame: Frame :: Maybe Int -> Maybe Text -> Text -> Maybe Int -> Maybe Text -> Maybe Text -> Frame
+ Patrol.Type.Frame: Frame :: Text -> Text -> Maybe Int -> Text -> Text -> Text -> Text -> Maybe Bool -> Text -> Maybe Int -> Text -> Text -> Maybe Platform -> [Text] -> [Text] -> Text -> Maybe Bool -> Text -> Map Text Value -> Frame
- Patrol.Type.Frame: [filename] :: Frame -> Maybe Text
+ Patrol.Type.Frame: [filename] :: Frame -> Text
- Patrol.Type.Frame: [module_] :: Frame -> Maybe Text
+ Patrol.Type.Frame: [module_] :: Frame -> Text
- Patrol.Type.Frame: [package] :: Frame -> Maybe Text
+ Patrol.Type.Frame: [package] :: Frame -> Text
- Patrol.Type.Frame: fromSrcLoc :: String -> SrcLoc -> Frame
+ Patrol.Type.Frame: fromSrcLoc :: SrcLoc -> Frame
- Patrol.Type.Request: Request :: Maybe (Map Text Text) -> Maybe Value -> Maybe (Map Text Text) -> Maybe (Map Text Text) -> Maybe Text -> Maybe (Map Text Text) -> Maybe Text -> Request
+ Patrol.Type.Request: Request :: Map Text Text -> Value -> Map Text Value -> Text -> Map Text Text -> Text -> Text -> Map Text Text -> Text -> Request
- Patrol.Type.Request: [cookies] :: Request -> Maybe (Map Text Text)
+ Patrol.Type.Request: [cookies] :: Request -> Map Text Text
- Patrol.Type.Request: [data_] :: Request -> Maybe Value
+ Patrol.Type.Request: [data_] :: Request -> Value
- Patrol.Type.Request: [env] :: Request -> Maybe (Map Text Text)
+ Patrol.Type.Request: [env] :: Request -> Map Text Value
- Patrol.Type.Request: [headers] :: Request -> Maybe (Map Text Text)
+ Patrol.Type.Request: [headers] :: Request -> Map Text Text
- Patrol.Type.Request: [method] :: Request -> Maybe Text
+ Patrol.Type.Request: [method] :: Request -> Text
- Patrol.Type.Request: [queryString] :: Request -> Maybe (Map Text Text)
+ Patrol.Type.Request: [queryString] :: Request -> Map Text Text
- Patrol.Type.Request: [url] :: Request -> Maybe Text
+ Patrol.Type.Request: [url] :: Request -> Text
- Patrol.Type.User: User :: Maybe Text -> Maybe Text -> Maybe Text -> Maybe Text -> User
+ Patrol.Type.User: User :: Map Text Value -> Text -> Maybe Geo -> Text -> Text -> Text -> Text -> Text -> User
- Patrol.Type.User: [email] :: User -> Maybe Text
+ Patrol.Type.User: [email] :: User -> Text
- Patrol.Type.User: [ipAddress] :: User -> Maybe Text
+ Patrol.Type.User: [ipAddress] :: User -> Text
- Patrol.Type.User: [username] :: User -> Maybe Text
+ Patrol.Type.User: [username] :: User -> Text
Files
- CHANGELOG.markdown +1/−1
- LICENSE.markdown +0/−13
- LICENSE.txt +21/−0
- patrol.cabal +151/−39
- source/library/Patrol.hs +100/−0
- source/library/Patrol/Client.hs +23/−0
- source/library/Patrol/Constant.hs +20/−0
- source/library/Patrol/Exception/Problem.hs +9/−0
- source/library/Patrol/Extra/Aeson.hs +20/−0
- source/library/Patrol/Extra/List.hs +16/−0
- source/library/Patrol/Type/AppContext.hs +45/−0
- source/library/Patrol/Type/AppleDebugImage.hs +44/−0
- source/library/Patrol/Type/Breadcrumb.hs +46/−0
- source/library/Patrol/Type/BreadcrumbType.hs +15/−0
- source/library/Patrol/Type/Breadcrumbs.hs +23/−0
- source/library/Patrol/Type/BrowserContext.hs +26/−0
- source/library/Patrol/Type/CError.hs +26/−0
- source/library/Patrol/Type/ClientSdkInfo.hs +33/−0
- source/library/Patrol/Type/ClientSdkPackage.hs +26/−0
- source/library/Patrol/Type/Context.hs +34/−0
- source/library/Patrol/Type/DebugImage.hs +22/−0
- source/library/Patrol/Type/DebugMeta.hs +27/−0
- source/library/Patrol/Type/DeviceContext.hs +129/−0
- source/library/Patrol/Type/Dsn.hs +91/−0
- source/library/Patrol/Type/ErrorType.hs +89/−0
- source/library/Patrol/Type/Event.hs +174/−0
- source/library/Patrol/Type/EventId.hs +61/−0
- source/library/Patrol/Type/EventProcessingError.hs +30/−0
- source/library/Patrol/Type/EventType.hs +24/−0
- source/library/Patrol/Type/Exception.hs +49/−0
- source/library/Patrol/Type/Exceptions.hs +23/−0
- source/library/Patrol/Type/Frame.hs +90/−0
- source/library/Patrol/Type/Geo.hs +29/−0
- source/library/Patrol/Type/GpuContext.hs +62/−0
- source/library/Patrol/Type/Level.hs +20/−0
- source/library/Patrol/Type/LogEntry.hs +29/−0
- source/library/Patrol/Type/MachException.hs +32/−0
- source/library/Patrol/Type/Mechanism.hs +43/−0
- source/library/Patrol/Type/MechanismMeta.hs +35/−0
- source/library/Patrol/Type/NativeDebugImage.hs +47/−0
- source/library/Patrol/Type/NsError.hs +26/−0
- source/library/Patrol/Type/OsContext.hs +38/−0
- source/library/Patrol/Type/Platform.hs +47/−0
- source/library/Patrol/Type/PosixSignal.hs +32/−0
- source/library/Patrol/Type/ProguardDebugImage.hs +23/−0
- source/library/Patrol/Type/Request.hs +48/−0
- source/library/Patrol/Type/Response.hs +21/−0
- source/library/Patrol/Type/RuntimeContext.hs +32/−0
- source/library/Patrol/Type/SpanStatus.hs +44/−0
- source/library/Patrol/Type/Stacktrace.hs +37/−0
- source/library/Patrol/Type/SystemSdkInfo.hs +32/−0
- source/library/Patrol/Type/Thread.hs +36/−0
- source/library/Patrol/Type/Threads.hs +23/−0
- source/library/Patrol/Type/TraceContext.hs +39/−0
- source/library/Patrol/Type/TransactionInfo.hs +27/−0
- source/library/Patrol/Type/TransactionSource.hs +24/−0
- source/library/Patrol/Type/User.hs +46/−0
- source/library/Patrol/Version.hs +14/−0
- source/test-suite/Main.hs +5/−0
- source/test-suite/Patrol/ClientSpec.hs +8/−0
- source/test-suite/Patrol/ConstantSpec.hs +25/−0
- source/test-suite/Patrol/Extra/AesonSpec.hs +57/−0
- source/test-suite/Patrol/Extra/ListSpec.hs +59/−0
- source/test-suite/Patrol/Type/AppContextSpec.hs +58/−0
- source/test-suite/Patrol/Type/AppleDebugImageSpec.hs +57/−0
- source/test-suite/Patrol/Type/BreadcrumbSpec.hs +57/−0
- source/test-suite/Patrol/Type/BreadcrumbTypeSpec.hs +20/−0
- source/test-suite/Patrol/Type/BreadcrumbsSpec.hs +24/−0
- source/test-suite/Patrol/Type/BrowserContextSpec.hs +27/−0
- source/test-suite/Patrol/Type/CErrorSpec.hs +27/−0
- source/test-suite/Patrol/Type/ClientSdkInfoSpec.hs +39/−0
- source/test-suite/Patrol/Type/ClientSdkPackageSpec.hs +27/−0
- source/test-suite/Patrol/Type/ContextSpec.hs +60/−0
- source/test-suite/Patrol/Type/DebugImageSpec.hs +39/−0
- source/test-suite/Patrol/Type/DebugMetaSpec.hs +32/−0
- source/test-suite/Patrol/Type/DeviceContextSpec.hs +198/−0
- source/test-suite/Patrol/Type/DsnSpec.hs +86/−0
- source/test-suite/Patrol/Type/ErrorTypeSpec.hs +131/−0
- source/test-suite/Patrol/Type/EventIdSpec.hs +74/−0
- source/test-suite/Patrol/Type/EventProcessingErrorSpec.hs +27/−0
- source/test-suite/Patrol/Type/EventSpec.hs +274/−0
- source/test-suite/Patrol/Type/EventTypeSpec.hs +32/−0
- source/test-suite/Patrol/Type/ExceptionSpec.hs +62/−0
- source/test-suite/Patrol/Type/ExceptionsSpec.hs +24/−0
- source/test-suite/Patrol/Type/FrameSpec.hs +137/−0
- source/test-suite/Patrol/Type/GeoSpec.hs +32/−0
- source/test-suite/Patrol/Type/GpuContextSpec.hs +87/−0
- source/test-suite/Patrol/Type/LevelSpec.hs +26/−0
- source/test-suite/Patrol/Type/LogEntrySpec.hs +32/−0
- source/test-suite/Patrol/Type/MachExceptionSpec.hs +37/−0
- source/test-suite/Patrol/Type/MechanismMetaSpec.hs +47/−0
- source/test-suite/Patrol/Type/MechanismSpec.hs +57/−0
- source/test-suite/Patrol/Type/NativeDebugImageSpec.hs +62/−0
- source/test-suite/Patrol/Type/NsErrorSpec.hs +27/−0
- source/test-suite/Patrol/Type/OsContextSpec.hs +47/−0
- source/test-suite/Patrol/Type/PlatformSpec.hs +68/−0
- source/test-suite/Patrol/Type/PosixSignalSpec.hs +37/−0
- source/test-suite/Patrol/Type/ProguardDebugImageSpec.hs +22/−0
- source/test-suite/Patrol/Type/RequestSpec.hs +63/−0
- source/test-suite/Patrol/Type/ResponseSpec.hs +24/−0
- source/test-suite/Patrol/Type/RuntimeContextSpec.hs +37/−0
- source/test-suite/Patrol/Type/SpanStatusSpec.hs +62/−0
- source/test-suite/Patrol/Type/StacktraceSpec.hs +102/−0
- source/test-suite/Patrol/Type/SystemSdkInfoSpec.hs +37/−0
- source/test-suite/Patrol/Type/ThreadSpec.hs +45/−0
- source/test-suite/Patrol/Type/ThreadsSpec.hs +23/−0
- source/test-suite/Patrol/Type/TraceContextSpec.hs +48/−0
- source/test-suite/Patrol/Type/TransactionInfoSpec.hs +28/−0
- source/test-suite/Patrol/Type/TransactionSourceSpec.hs +32/−0
- source/test-suite/Patrol/Type/UserSpec.hs +60/−0
- source/test-suite/PatrolSpec.hs +108/−0
- src/lib/Patrol.hs +0/−28
- src/lib/Patrol/Client.hs +0/−63
- src/lib/Patrol/Type/Dsn.hs +0/−75
- src/lib/Patrol/Type/Event.hs +0/−86
- src/lib/Patrol/Type/EventId.hs +0/−30
- src/lib/Patrol/Type/Exception.hs +0/−38
- src/lib/Patrol/Type/Frame.hs +0/−40
- src/lib/Patrol/Type/Level.hs +0/−22
- src/lib/Patrol/Type/Platform.hs +0/−50
- src/lib/Patrol/Type/Request.hs +0/−30
- src/lib/Patrol/Type/Response.hs +0/−17
- src/lib/Patrol/Type/StackTrace.hs +0/−25
- src/lib/Patrol/Type/Timestamp.hs +0/−22
- src/lib/Patrol/Type/User.hs +0/−23
- src/lib/Patrol/Utility/Json.hs +0/−14
- src/lib/Patrol/Utility/Maybe.hs +0/−6
CHANGELOG.markdown view
@@ -1,4 +1,4 @@ # Change log -Patrol uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).+Patrol uses the [Package Versioning Policy](https://pvp.haskell.org). The change log is available through [the releases](https://github.com/tfausak/patrol/releases) on GitHub.
− LICENSE.markdown
@@ -1,13 +0,0 @@-Copyright 2022 Taylor Fausak--Permission to use, copy, modify, and/or distribute this software for any-purpose with or without fee is hereby granted, provided that the above-copyright notice and this permission notice appear in all copies.--THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH-REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND-FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,-INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM-LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR-OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR-PERFORMANCE OF THIS SOFTWARE.
+ LICENSE.txt view
@@ -0,0 +1,21 @@+MIT License++Copyright (c) 2022 Taylor Fausak++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.
patrol.cabal view
@@ -1,72 +1,184 @@-cabal-version: 2.0+cabal-version: 2.2 name: patrol-version: 0.0.4+version: 0.1.0.1 synopsis: Sentry SDK description: Patrol is a Sentry SDK. build-type: Simple category: Exceptions-extra-source-files:- CHANGELOG.markdown- README.markdown-license-file: LICENSE.markdown-license: ISC+extra-source-files: CHANGELOG.markdown README.markdown+license-file: LICENSE.txt+license: MIT maintainer: Taylor Fausak source-repository head location: https://github.com/tfausak/patrol type: git -library- autogen-modules: Paths_patrol+flag pedantic+ default: False+ manual: True++common library build-depends:- base >= 4.13.0 && < 4.17- , aeson >= 1.4.6 && < 1.6 || >= 2.0.3 && < 2.2- , bytestring >= 0.10.10 && < 0.12+ , aeson >= 2.1 && < 2.2+ , base >= 4.15 && < 4.18+ , bytestring >= 0.10.12 && < 0.12 , case-insensitive >= 1.2.1 && < 1.3- , containers >= 0.6.2 && < 0.7- , http-client >= 0.6.4 && < 0.8+ , containers >= 0.6.4 && < 0.7+ , exceptions >= 0.10.4 && < 0.11+ , http-client >= 0.7.13 && < 0.8 , http-types >= 0.12.3 && < 0.13- , network-uri >= 2.6.2 && < 2.7- , text >= 1.2.4 && < 1.3 || >= 2.0 && < 2.1- , time >= 1.9.3 && < 1.12- , uuid >= 1.3.13 && < 1.4- default-extensions: NamedFieldPuns+ , network-uri >= 2.6.4 && < 2.7+ , text >= 1.2.4 && < 1.3 || >= 2.0.1 && < 2.1+ , time >= 1.9.3 && < 1.13+ , uuid >= 1.3.15 && < 1.4 default-language: Haskell2010+ ghc-options:+ -Weverything+ -Wno-all-missed-specialisations+ -Wno-implicit-prelude+ -Wno-missed-specialisations+ -Wno-missing-deriving-strategies+ -Wno-missing-export-lists+ -Wno-missing-safe-haskell-mode+ -Wno-prepositive-qualified-module+ -Wno-safe+ -Wno-unsafe++ if impl(ghc >= 9.2)+ ghc-options: -Wno-missing-kind-signatures++ if flag(pedantic)+ ghc-options: -Werror++common executable+ import: library++ build-depends: patrol+ ghc-options: -rtsopts -threaded++library+ import: library++ autogen-modules: Paths_patrol exposed-modules: Patrol Patrol.Client- Patrol.Utility.Json- Patrol.Utility.Maybe+ Patrol.Constant+ Patrol.Exception.Problem+ Patrol.Extra.Aeson+ Patrol.Extra.List+ Patrol.Type.AppContext+ Patrol.Type.AppleDebugImage+ Patrol.Type.Breadcrumb+ Patrol.Type.Breadcrumbs+ Patrol.Type.BreadcrumbType+ Patrol.Type.BrowserContext+ Patrol.Type.CError+ Patrol.Type.ClientSdkInfo+ Patrol.Type.ClientSdkPackage+ Patrol.Type.Context+ Patrol.Type.DebugImage+ Patrol.Type.DebugMeta+ Patrol.Type.DeviceContext Patrol.Type.Dsn+ Patrol.Type.ErrorType Patrol.Type.Event Patrol.Type.EventId+ Patrol.Type.EventProcessingError+ Patrol.Type.EventType Patrol.Type.Exception+ Patrol.Type.Exceptions Patrol.Type.Frame+ Patrol.Type.Geo+ Patrol.Type.GpuContext Patrol.Type.Level+ Patrol.Type.LogEntry+ Patrol.Type.MachException+ Patrol.Type.Mechanism+ Patrol.Type.MechanismMeta+ Patrol.Type.NativeDebugImage+ Patrol.Type.NsError+ Patrol.Type.OsContext Patrol.Type.Platform+ Patrol.Type.PosixSignal+ Patrol.Type.ProguardDebugImage Patrol.Type.Request Patrol.Type.Response- Patrol.Type.StackTrace- Patrol.Type.Timestamp+ Patrol.Type.RuntimeContext+ Patrol.Type.SpanStatus+ Patrol.Type.Stacktrace+ Patrol.Type.SystemSdkInfo+ Patrol.Type.Thread+ Patrol.Type.Threads+ Patrol.Type.TraceContext+ Patrol.Type.TransactionInfo+ Patrol.Type.TransactionSource Patrol.Type.User- ghc-options:- -Weverything- -Wno-all-missed-specialisations- -Wno-implicit-prelude- -Wno-missing-deriving-strategies- -Wno-missing-exported-signatures- -Wno-safe- -Wno-unsafe- hs-source-dirs: src/lib+ Patrol.Version+ hs-source-dirs: source/library other-modules: Paths_patrol - if impl(ghc >= 8.10)- ghc-options:- -Wno-missing-safe-haskell-mode- -Wno-prepositive-qualified-module+test-suite patrol-test-suite+ import: executable - if impl(ghc >= 9.2)- ghc-options:- -Wno-missing-kind-signatures+ build-depends:+ , hspec >= 2.10.6 && < 2.11+ hs-source-dirs: source/test-suite+ main-is: Main.hs+ other-modules:+ Patrol.ClientSpec+ Patrol.ConstantSpec+ Patrol.Extra.AesonSpec+ Patrol.Extra.ListSpec+ Patrol.Type.AppContextSpec+ Patrol.Type.AppleDebugImageSpec+ Patrol.Type.BreadcrumbSpec+ Patrol.Type.BreadcrumbsSpec+ Patrol.Type.BreadcrumbTypeSpec+ Patrol.Type.BrowserContextSpec+ Patrol.Type.CErrorSpec+ Patrol.Type.ClientSdkInfoSpec+ Patrol.Type.ClientSdkPackageSpec+ Patrol.Type.ContextSpec+ Patrol.Type.DebugImageSpec+ Patrol.Type.DebugMetaSpec+ Patrol.Type.DeviceContextSpec+ Patrol.Type.DsnSpec+ Patrol.Type.ErrorTypeSpec+ Patrol.Type.EventIdSpec+ Patrol.Type.EventProcessingErrorSpec+ Patrol.Type.EventSpec+ Patrol.Type.EventTypeSpec+ Patrol.Type.ExceptionSpec+ Patrol.Type.ExceptionsSpec+ Patrol.Type.FrameSpec+ Patrol.Type.GeoSpec+ Patrol.Type.GpuContextSpec+ Patrol.Type.LevelSpec+ Patrol.Type.LogEntrySpec+ Patrol.Type.MachExceptionSpec+ Patrol.Type.MechanismMetaSpec+ Patrol.Type.MechanismSpec+ Patrol.Type.NativeDebugImageSpec+ Patrol.Type.NsErrorSpec+ Patrol.Type.OsContextSpec+ Patrol.Type.PlatformSpec+ Patrol.Type.PosixSignalSpec+ Patrol.Type.ProguardDebugImageSpec+ Patrol.Type.RequestSpec+ Patrol.Type.ResponseSpec+ Patrol.Type.RuntimeContextSpec+ Patrol.Type.SpanStatusSpec+ Patrol.Type.StacktraceSpec+ Patrol.Type.SystemSdkInfoSpec+ Patrol.Type.ThreadSpec+ Patrol.Type.ThreadsSpec+ Patrol.Type.TraceContextSpec+ Patrol.Type.TransactionInfoSpec+ Patrol.Type.TransactionSourceSpec+ Patrol.Type.UserSpec+ PatrolSpec+ type: exitcode-stdio-1.0
+ source/library/Patrol.hs view
@@ -0,0 +1,100 @@+module Patrol+ ( Patrol.Exception.Problem.Problem,+ Patrol.Type.AppContext.AppContext,+ Patrol.Type.AppleDebugImage.AppleDebugImage,+ Patrol.Type.Breadcrumb.Breadcrumb,+ Patrol.Type.Breadcrumbs.Breadcrumbs,+ Patrol.Type.BreadcrumbType.BreadcrumbType,+ Patrol.Type.BrowserContext.BrowserContext,+ Patrol.Type.CError.CError,+ Patrol.Type.ClientSdkInfo.ClientSdkInfo,+ Patrol.Type.ClientSdkPackage.ClientSdkPackage,+ Patrol.Type.Context.Context,+ Patrol.Type.DebugImage.DebugImage,+ Patrol.Type.DebugMeta.DebugMeta,+ Patrol.Type.DeviceContext.DeviceContext,+ Patrol.Type.Dsn.Dsn,+ Patrol.Type.ErrorType.ErrorType,+ Patrol.Type.Event.Event,+ Patrol.Type.EventId.EventId,+ Patrol.Type.EventProcessingError.EventProcessingError,+ Patrol.Type.EventType.EventType,+ Patrol.Type.Exception.Exception,+ Patrol.Type.Exceptions.Exceptions,+ Patrol.Type.Frame.Frame,+ Patrol.Type.Geo.Geo,+ Patrol.Type.GpuContext.GpuContext,+ Patrol.Type.Level.Level,+ Patrol.Type.LogEntry.LogEntry,+ Patrol.Type.MachException.MachException,+ Patrol.Type.Mechanism.Mechanism,+ Patrol.Type.MechanismMeta.MechanismMeta,+ Patrol.Type.NativeDebugImage.NativeDebugImage,+ Patrol.Type.NsError.NsError,+ Patrol.Type.OsContext.OsContext,+ Patrol.Type.Platform.Platform,+ Patrol.Type.PosixSignal.PosixSignal,+ Patrol.Type.ProguardDebugImage.ProguardDebugImage,+ Patrol.Type.Request.Request,+ Patrol.Type.Response.Response,+ Patrol.Type.RuntimeContext.RuntimeContext,+ Patrol.Type.SpanStatus.SpanStatus,+ Patrol.Type.Stacktrace.Stacktrace,+ Patrol.Type.SystemSdkInfo.SystemSdkInfo,+ Patrol.Type.Thread.Thread,+ Patrol.Type.Threads.Threads,+ Patrol.Type.TraceContext.TraceContext,+ Patrol.Type.TransactionInfo.TransactionInfo,+ Patrol.Type.TransactionSource.TransactionSource,+ Patrol.Type.User.User,+ )+where++import qualified Patrol.Exception.Problem+import qualified Patrol.Type.AppContext+import qualified Patrol.Type.AppleDebugImage+import qualified Patrol.Type.Breadcrumb+import qualified Patrol.Type.BreadcrumbType+import qualified Patrol.Type.Breadcrumbs+import qualified Patrol.Type.BrowserContext+import qualified Patrol.Type.CError+import qualified Patrol.Type.ClientSdkInfo+import qualified Patrol.Type.ClientSdkPackage+import qualified Patrol.Type.Context+import qualified Patrol.Type.DebugImage+import qualified Patrol.Type.DebugMeta+import qualified Patrol.Type.DeviceContext+import qualified Patrol.Type.Dsn+import qualified Patrol.Type.ErrorType+import qualified Patrol.Type.Event+import qualified Patrol.Type.EventId+import qualified Patrol.Type.EventProcessingError+import qualified Patrol.Type.EventType+import qualified Patrol.Type.Exception+import qualified Patrol.Type.Exceptions+import qualified Patrol.Type.Frame+import qualified Patrol.Type.Geo+import qualified Patrol.Type.GpuContext+import qualified Patrol.Type.Level+import qualified Patrol.Type.LogEntry+import qualified Patrol.Type.MachException+import qualified Patrol.Type.Mechanism+import qualified Patrol.Type.MechanismMeta+import qualified Patrol.Type.NativeDebugImage+import qualified Patrol.Type.NsError+import qualified Patrol.Type.OsContext+import qualified Patrol.Type.Platform+import qualified Patrol.Type.PosixSignal+import qualified Patrol.Type.ProguardDebugImage+import qualified Patrol.Type.Request+import qualified Patrol.Type.Response+import qualified Patrol.Type.RuntimeContext+import qualified Patrol.Type.SpanStatus+import qualified Patrol.Type.Stacktrace+import qualified Patrol.Type.SystemSdkInfo+import qualified Patrol.Type.Thread+import qualified Patrol.Type.Threads+import qualified Patrol.Type.TraceContext+import qualified Patrol.Type.TransactionInfo+import qualified Patrol.Type.TransactionSource+import qualified Patrol.Type.User
+ source/library/Patrol/Client.hs view
@@ -0,0 +1,23 @@+module Patrol.Client where++import qualified Control.Monad.Catch as Catch+import qualified Control.Monad.IO.Class as IO+import qualified Data.Aeson as Aeson+import qualified Network.HTTP.Client as Client+import qualified Patrol.Exception.Problem as Problem+import qualified Patrol.Type.Dsn as Dsn+import qualified Patrol.Type.Event as Event+import qualified Patrol.Type.Response as Response++store ::+ (IO.MonadIO io, Catch.MonadThrow io) =>+ Client.Manager ->+ Dsn.Dsn ->+ Event.Event ->+ io Response.Response+store manager dsn event = do+ request <- Event.intoRequest dsn event+ response <- IO.liftIO $ Client.httpLbs request manager+ either (Catch.throwM . Problem.Problem . mappend "invalid response body: ") pure+ . Aeson.eitherDecode+ $ Client.responseBody response
+ source/library/Patrol/Constant.hs view
@@ -0,0 +1,20 @@+module Patrol.Constant where++import qualified Data.ByteString as ByteString+import qualified Data.CaseInsensitive as CI+import qualified Data.Text as Text+import qualified Data.Text.Encoding as Text+import qualified Network.HTTP.Types as Http+import qualified Patrol.Version as Version++applicationJson :: ByteString.ByteString+applicationJson = Text.encodeUtf8 $ Text.pack "application/json"++sentryVersion :: Text.Text+sentryVersion = Text.singleton '7'++userAgent :: Text.Text+userAgent = Text.pack "patrol/" <> Version.text++xSentryAuth :: Http.HeaderName+xSentryAuth = CI.mk . Text.encodeUtf8 $ Text.pack "X-Sentry-Auth"
+ source/library/Patrol/Exception/Problem.hs view
@@ -0,0 +1,9 @@+module Patrol.Exception.Problem where++import qualified Control.Monad.Catch as Catch++newtype Problem+ = Problem String+ deriving (Eq, Show)++instance Catch.Exception Problem
+ source/library/Patrol/Extra/Aeson.hs view
@@ -0,0 +1,20 @@+module Patrol.Extra.Aeson where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.Key as Key+import qualified Data.Aeson.Types as Aeson+import qualified Data.Text as Text++intoObject :: [Aeson.Pair] -> Aeson.Value+intoObject = Aeson.object . filter (not . isEmpty . snd)++isEmpty :: Aeson.Value -> Bool+isEmpty value = case value of+ Aeson.Array array -> null array+ Aeson.Null -> True+ Aeson.Object object -> null object+ Aeson.String string -> Text.null string+ _ -> False++pair :: Aeson.ToJSON a => String -> a -> Aeson.Pair+pair = (Aeson..=) . Key.fromString
+ source/library/Patrol/Extra/List.hs view
@@ -0,0 +1,16 @@+module Patrol.Extra.List where++import qualified Data.Function as Function++insertAll :: Eq k => [(k, v)] -> [(k, v)] -> [(k, v)]+insertAll = flip $ foldr insert++insert :: Eq k => (k, v) -> [(k, v)] -> [(k, v)]+insert = insertBy $ Function.on (==) fst++insertBy :: (a -> a -> Bool) -> a -> [a] -> [a]+insertBy p x xs = case xs of+ [] -> [x]+ h : t+ | p x h -> h : t+ | otherwise -> h : insertBy p x t
+ source/library/Patrol/Type/AppContext.hs view
@@ -0,0 +1,45 @@+module Patrol.Type.AppContext where++import qualified Data.Aeson as Aeson+import qualified Data.Text as Text+import qualified Data.Time as Time+import qualified Patrol.Extra.Aeson as Aeson++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#appcontext>+data AppContext = AppContext+ { appBuild :: Text.Text,+ appIdentifier :: Text.Text,+ appMemory :: Maybe Int,+ appName :: Text.Text,+ appStartTime :: Maybe Time.UTCTime,+ appVersion :: Text.Text,+ buildType :: Text.Text,+ deviceAppHash :: Text.Text+ }+ deriving (Eq, Show)++instance Aeson.ToJSON AppContext where+ toJSON appContext =+ Aeson.intoObject+ [ Aeson.pair "app_build" $ appBuild appContext,+ Aeson.pair "app_identifier" $ appIdentifier appContext,+ Aeson.pair "app_memory" $ appMemory appContext,+ Aeson.pair "app_name" $ appName appContext,+ Aeson.pair "app_start_time" $ appStartTime appContext,+ Aeson.pair "app_version" $ appVersion appContext,+ Aeson.pair "build_type" $ buildType appContext,+ Aeson.pair "device_app_hash" $ deviceAppHash appContext+ ]++empty :: AppContext+empty =+ AppContext+ { appBuild = Text.empty,+ appIdentifier = Text.empty,+ appMemory = Nothing,+ appName = Text.empty,+ appStartTime = Nothing,+ appVersion = Text.empty,+ buildType = Text.empty,+ deviceAppHash = Text.empty+ }
+ source/library/Patrol/Type/AppleDebugImage.hs view
@@ -0,0 +1,44 @@+module Patrol.Type.AppleDebugImage where++import qualified Data.Aeson as Aeson+import qualified Data.Text as Text+import qualified Patrol.Extra.Aeson as Aeson++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#appledebugimage>+data AppleDebugImage = AppleDebugImage+ { arch :: Text.Text,+ cpuSubtype :: Maybe Int,+ cpuType :: Maybe Int,+ imageAddr :: Text.Text,+ imageSize :: Maybe Int,+ imageVmaddr :: Text.Text,+ name :: Text.Text,+ uuid :: Text.Text+ }+ deriving (Eq, Show)++instance Aeson.ToJSON AppleDebugImage where+ toJSON appleDebugImage =+ Aeson.intoObject+ [ Aeson.pair "arch" $ arch appleDebugImage,+ Aeson.pair "cpu_subtype" $ cpuSubtype appleDebugImage,+ Aeson.pair "cpu_type" $ cpuType appleDebugImage,+ Aeson.pair "image_addr" $ imageAddr appleDebugImage,+ Aeson.pair "image_size" $ imageSize appleDebugImage,+ Aeson.pair "image_vmaddr" $ imageVmaddr appleDebugImage,+ Aeson.pair "name" $ name appleDebugImage,+ Aeson.pair "uuid" $ uuid appleDebugImage+ ]++empty :: AppleDebugImage+empty =+ AppleDebugImage+ { arch = Text.empty,+ cpuSubtype = Nothing,+ cpuType = Nothing,+ imageAddr = Text.empty,+ imageSize = Nothing,+ imageVmaddr = Text.empty,+ name = Text.empty,+ uuid = Text.empty+ }
+ source/library/Patrol/Type/Breadcrumb.hs view
@@ -0,0 +1,46 @@+module Patrol.Type.Breadcrumb where++import qualified Data.Aeson as Aeson+import qualified Data.Map as Map+import qualified Data.Text as Text+import qualified Data.Time as Time+import qualified Patrol.Extra.Aeson as Aeson+import qualified Patrol.Type.BreadcrumbType as BreadcrumbType+import qualified Patrol.Type.EventId as EventId+import qualified Patrol.Type.Level as Level++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#breadcrumb>+data Breadcrumb = Breadcrumb+ { category :: Text.Text,+ data_ :: Map.Map Text.Text Aeson.Value,+ eventId :: Maybe EventId.EventId,+ level :: Maybe Level.Level,+ message :: Text.Text,+ timestamp :: Maybe Time.UTCTime,+ type_ :: Maybe BreadcrumbType.BreadcrumbType+ }+ deriving (Eq, Show)++instance Aeson.ToJSON Breadcrumb where+ toJSON breadcrumb =+ Aeson.intoObject+ [ Aeson.pair "category" $ category breadcrumb,+ Aeson.pair "data" $ data_ breadcrumb,+ Aeson.pair "event_id" $ eventId breadcrumb,+ Aeson.pair "level" $ level breadcrumb,+ Aeson.pair "message" $ message breadcrumb,+ Aeson.pair "timestamp" $ timestamp breadcrumb,+ Aeson.pair "type" $ type_ breadcrumb+ ]++empty :: Breadcrumb+empty =+ Breadcrumb+ { category = Text.empty,+ data_ = Map.empty,+ eventId = Nothing,+ level = Nothing,+ message = Text.empty,+ timestamp = Nothing,+ type_ = Nothing+ }
+ source/library/Patrol/Type/BreadcrumbType.hs view
@@ -0,0 +1,15 @@+module Patrol.Type.BreadcrumbType where++import qualified Data.Aeson as Aeson++data BreadcrumbType+ = Default+ | Http+ | Navigation+ deriving (Eq, Show)++instance Aeson.ToJSON BreadcrumbType where+ toJSON breadcrumbType = Aeson.toJSON $ case breadcrumbType of+ Default -> "default"+ Http -> "http"+ Navigation -> "navigation"
+ source/library/Patrol/Type/Breadcrumbs.hs view
@@ -0,0 +1,23 @@+module Patrol.Type.Breadcrumbs where++import qualified Data.Aeson as Aeson+import qualified Patrol.Extra.Aeson as Aeson+import qualified Patrol.Type.Breadcrumb as Breadcrumb++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#breadcrumbs>+newtype Breadcrumbs = Breadcrumbs+ { values :: [Breadcrumb.Breadcrumb]+ }+ deriving (Eq, Show)++instance Aeson.ToJSON Breadcrumbs where+ toJSON breadcrumbs =+ Aeson.intoObject+ [ Aeson.pair "values" $ values breadcrumbs+ ]++empty :: Breadcrumbs+empty =+ Breadcrumbs+ { values = []+ }
+ source/library/Patrol/Type/BrowserContext.hs view
@@ -0,0 +1,26 @@+module Patrol.Type.BrowserContext where++import qualified Data.Aeson as Aeson+import qualified Data.Text as Text+import qualified Patrol.Extra.Aeson as Aeson++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#browsercontext>+data BrowserContext = BrowserContext+ { name :: Text.Text,+ version :: Text.Text+ }+ deriving (Eq, Show)++instance Aeson.ToJSON BrowserContext where+ toJSON browserContext =+ Aeson.intoObject+ [ Aeson.pair "name" $ name browserContext,+ Aeson.pair "version" $ version browserContext+ ]++empty :: BrowserContext+empty =+ BrowserContext+ { name = Text.empty,+ version = Text.empty+ }
+ source/library/Patrol/Type/CError.hs view
@@ -0,0 +1,26 @@+module Patrol.Type.CError where++import qualified Data.Aeson as Aeson+import qualified Data.Text as Text+import qualified Patrol.Extra.Aeson as Aeson++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#cerror>+data CError = CError+ { name :: Text.Text,+ number :: Maybe Int+ }+ deriving (Eq, Show)++instance Aeson.ToJSON CError where+ toJSON cError =+ Aeson.intoObject+ [ Aeson.pair "name" $ name cError,+ Aeson.pair "number" $ number cError+ ]++empty :: CError+empty =+ CError+ { name = Text.empty,+ number = Nothing+ }
+ source/library/Patrol/Type/ClientSdkInfo.hs view
@@ -0,0 +1,33 @@+module Patrol.Type.ClientSdkInfo where++import qualified Data.Aeson as Aeson+import qualified Data.Text as Text+import qualified Patrol.Extra.Aeson as Aeson+import qualified Patrol.Type.ClientSdkPackage as ClientSdkPackage++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#clientsdkinfo>+data ClientSdkInfo = ClientSdkInfo+ { integrations :: [Text.Text],+ name :: Text.Text,+ packages :: [ClientSdkPackage.ClientSdkPackage],+ version :: Text.Text+ }+ deriving (Eq, Show)++instance Aeson.ToJSON ClientSdkInfo where+ toJSON clientSdkInfo =+ Aeson.intoObject+ [ Aeson.pair "integrations" $ integrations clientSdkInfo,+ Aeson.pair "name" $ name clientSdkInfo,+ Aeson.pair "packages" $ packages clientSdkInfo,+ Aeson.pair "version" $ version clientSdkInfo+ ]++empty :: ClientSdkInfo+empty =+ ClientSdkInfo+ { integrations = [],+ name = Text.empty,+ packages = [],+ version = Text.empty+ }
+ source/library/Patrol/Type/ClientSdkPackage.hs view
@@ -0,0 +1,26 @@+module Patrol.Type.ClientSdkPackage where++import qualified Data.Aeson as Aeson+import qualified Data.Text as Text+import qualified Patrol.Extra.Aeson as Aeson++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#clientsdkpackage>+data ClientSdkPackage = ClientSdkPackage+ { name :: Text.Text,+ version :: Text.Text+ }+ deriving (Eq, Show)++instance Aeson.ToJSON ClientSdkPackage where+ toJSON clientSdkPackage =+ Aeson.intoObject+ [ Aeson.pair "name" $ name clientSdkPackage,+ Aeson.pair "version" $ version clientSdkPackage+ ]++empty :: ClientSdkPackage+empty =+ ClientSdkPackage+ { name = Text.empty,+ version = Text.empty+ }
+ source/library/Patrol/Type/Context.hs view
@@ -0,0 +1,34 @@+module Patrol.Type.Context where++import qualified Data.Aeson as Aeson+import qualified Data.Map as Map+import qualified Data.Text as Text+import qualified Patrol.Type.AppContext as AppContext+import qualified Patrol.Type.BrowserContext as BrowserContext+import qualified Patrol.Type.DeviceContext as DeviceContext+import qualified Patrol.Type.GpuContext as GpuContext+import qualified Patrol.Type.OsContext as OsContext+import qualified Patrol.Type.RuntimeContext as RuntimeContext+import qualified Patrol.Type.TraceContext as TraceContext++data Context+ = App AppContext.AppContext+ | Browser BrowserContext.BrowserContext+ | Device DeviceContext.DeviceContext+ | Gpu GpuContext.GpuContext+ | Os OsContext.OsContext+ | Runtime RuntimeContext.RuntimeContext+ | Trace TraceContext.TraceContext+ | Other (Map.Map Text.Text Aeson.Value)+ deriving (Eq, Show)++instance Aeson.ToJSON Context where+ toJSON context = case context of+ App appContext -> Aeson.toJSON appContext+ Browser browserContext -> Aeson.toJSON browserContext+ Device deviceContext -> Aeson.toJSON deviceContext+ Gpu gpuContext -> Aeson.toJSON gpuContext+ Os osContext -> Aeson.toJSON osContext+ Runtime runtimeContext -> Aeson.toJSON runtimeContext+ Trace traceContext -> Aeson.toJSON traceContext+ Other other -> Aeson.toJSON other
+ source/library/Patrol/Type/DebugImage.hs view
@@ -0,0 +1,22 @@+module Patrol.Type.DebugImage where++import qualified Data.Aeson as Aeson+import qualified Data.Map as Map+import qualified Data.Text as Text+import qualified Patrol.Type.AppleDebugImage as AppleDebugImage+import qualified Patrol.Type.NativeDebugImage as NativeDebugImage+import qualified Patrol.Type.ProguardDebugImage as ProguardDebugImage++data DebugImage+ = Apple AppleDebugImage.AppleDebugImage+ | Native NativeDebugImage.NativeDebugImage+ | Proguard ProguardDebugImage.ProguardDebugImage+ | Other (Map.Map Text.Text Aeson.Value)+ deriving (Eq, Show)++instance Aeson.ToJSON DebugImage where+ toJSON debugImage = case debugImage of+ Apple appleDebugImage -> Aeson.toJSON appleDebugImage+ Native nativeDebugImage -> Aeson.toJSON nativeDebugImage+ Proguard proguardDebugImage -> Aeson.toJSON proguardDebugImage+ Other other -> Aeson.toJSON other
+ source/library/Patrol/Type/DebugMeta.hs view
@@ -0,0 +1,27 @@+module Patrol.Type.DebugMeta where++import qualified Data.Aeson as Aeson+import qualified Patrol.Extra.Aeson as Aeson+import qualified Patrol.Type.DebugImage as DebugImage+import qualified Patrol.Type.SystemSdkInfo as SystemSdkInfo++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#debugmeta>+data DebugMeta = DebugMeta+ { images :: [DebugImage.DebugImage],+ sdkInfo :: Maybe SystemSdkInfo.SystemSdkInfo+ }+ deriving (Eq, Show)++instance Aeson.ToJSON DebugMeta where+ toJSON debugMeta =+ Aeson.intoObject+ [ Aeson.pair "images" $ images debugMeta,+ Aeson.pair "sdk_info" $ sdkInfo debugMeta+ ]++empty :: DebugMeta+empty =+ DebugMeta+ { images = [],+ sdkInfo = Nothing+ }
+ source/library/Patrol/Type/DeviceContext.hs view
@@ -0,0 +1,129 @@+module Patrol.Type.DeviceContext where++import qualified Data.Aeson as Aeson+import qualified Data.Text as Text+import qualified Data.Time as Time+import qualified Patrol.Extra.Aeson as Aeson++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#devicecontext>+data DeviceContext = DeviceContext+ { arch :: Text.Text,+ batteryLevel :: Maybe Double,+ batteryStatus :: Text.Text,+ bootTime :: Maybe Time.UTCTime,+ brand :: Text.Text,+ charging :: Maybe Bool,+ cpuDescription :: Text.Text,+ deviceType :: Text.Text,+ deviceUniqueIdentifier :: Text.Text,+ externalFreeStorage :: Maybe Int,+ externalStorageSize :: Maybe Int,+ family :: Text.Text,+ freeMemory :: Maybe Int,+ freeStorage :: Maybe Int,+ lowMemory :: Maybe Bool,+ manufacturer :: Text.Text,+ memorySize :: Maybe Int,+ model :: Text.Text,+ modelId :: Text.Text,+ name :: Text.Text,+ online :: Maybe Bool,+ orientation :: Text.Text,+ processorCount :: Maybe Int,+ processorFrequency :: Maybe Double,+ screenDensity :: Maybe Double,+ screenDpi :: Maybe Double,+ screenResolution :: Text.Text,+ simulator :: Maybe Bool,+ storageSize :: Maybe Int,+ supportsAccelerometer :: Maybe Bool,+ supportsAudio :: Maybe Bool,+ supportsGyroscope :: Maybe Bool,+ supportsLocationService :: Maybe Bool,+ supportsVibration :: Maybe Bool,+ timezone :: Text.Text,+ usableMemory :: Maybe Int+ }+ deriving (Eq, Show)++instance Aeson.ToJSON DeviceContext where+ toJSON deviceContext =+ Aeson.intoObject+ [ Aeson.pair "arch" $ arch deviceContext,+ Aeson.pair "battery_level" $ batteryLevel deviceContext,+ Aeson.pair "battery_status" $ batteryStatus deviceContext,+ Aeson.pair "boot_time" $ bootTime deviceContext,+ Aeson.pair "brand" $ brand deviceContext,+ Aeson.pair "charging" $ charging deviceContext,+ Aeson.pair "cpu_description" $ cpuDescription deviceContext,+ Aeson.pair "device_type" $ deviceType deviceContext,+ Aeson.pair "device_unique_identifier" $ deviceUniqueIdentifier deviceContext,+ Aeson.pair "external_free_storage" $ externalFreeStorage deviceContext,+ Aeson.pair "external_storage_size" $ externalStorageSize deviceContext,+ Aeson.pair "family" $ family deviceContext,+ Aeson.pair "free_memory" $ freeMemory deviceContext,+ Aeson.pair "free_storage" $ freeStorage deviceContext,+ Aeson.pair "low_memory" $ lowMemory deviceContext,+ Aeson.pair "manufacturer" $ manufacturer deviceContext,+ Aeson.pair "memory_size" $ memorySize deviceContext,+ Aeson.pair "model" $ model deviceContext,+ Aeson.pair "model_id" $ modelId deviceContext,+ Aeson.pair "name" $ name deviceContext,+ Aeson.pair "online" $ online deviceContext,+ Aeson.pair "orientation" $ orientation deviceContext,+ Aeson.pair "processor_count" $ processorCount deviceContext,+ Aeson.pair "processor_frequency" $ processorFrequency deviceContext,+ Aeson.pair "screen_density" $ screenDensity deviceContext,+ Aeson.pair "screen_dpi" $ screenDpi deviceContext,+ Aeson.pair "screen_resolution" $ screenResolution deviceContext,+ Aeson.pair "simulator" $ simulator deviceContext,+ Aeson.pair "storage_size" $ storageSize deviceContext,+ Aeson.pair "supports_accelerometer" $ supportsAccelerometer deviceContext,+ Aeson.pair "supports_audio" $ supportsAudio deviceContext,+ Aeson.pair "supports_gyroscope" $ supportsGyroscope deviceContext,+ Aeson.pair "supports_location_service" $ supportsLocationService deviceContext,+ Aeson.pair "supports_vibration" $ supportsVibration deviceContext,+ Aeson.pair "timezone" $ timezone deviceContext,+ Aeson.pair "usable_memory" $ usableMemory deviceContext+ ]++empty :: DeviceContext+empty =+ DeviceContext+ { arch = Text.empty,+ batteryLevel = Nothing,+ batteryStatus = Text.empty,+ bootTime = Nothing,+ brand = Text.empty,+ charging = Nothing,+ cpuDescription = Text.empty,+ deviceType = Text.empty,+ deviceUniqueIdentifier = Text.empty,+ externalFreeStorage = Nothing,+ externalStorageSize = Nothing,+ family = Text.empty,+ freeMemory = Nothing,+ freeStorage = Nothing,+ lowMemory = Nothing,+ manufacturer = Text.empty,+ memorySize = Nothing,+ model = Text.empty,+ modelId = Text.empty,+ name = Text.empty,+ online = Nothing,+ orientation = Text.empty,+ processorCount = Nothing,+ processorFrequency = Nothing,+ screenDensity = Nothing,+ screenDpi = Nothing,+ screenResolution = Text.empty,+ simulator = Nothing,+ storageSize = Nothing,+ supportsAccelerometer = Nothing,+ supportsAudio = Nothing,+ supportsGyroscope = Nothing,+ supportsLocationService = Nothing,+ supportsVibration = Nothing,+ timezone = Text.empty,+ usableMemory = Nothing+ }
+ source/library/Patrol/Type/Dsn.hs view
@@ -0,0 +1,91 @@+module Patrol.Type.Dsn where++import qualified Control.Monad as Monad+import qualified Control.Monad.Catch as Catch+import qualified Data.ByteString as ByteString+import qualified Data.Maybe as Maybe+import qualified Data.Text as Text+import qualified Data.Text.Encoding as Text+import qualified Network.URI as Uri+import qualified Numeric.Natural as Natural+import qualified Patrol.Constant as Constant+import qualified Patrol.Exception.Problem as Problem+import qualified Text.Read as Read++data Dsn = Dsn+ { protocol :: Text.Text,+ publicKey :: Text.Text,+ secretKey :: Text.Text,+ host :: Text.Text,+ port :: Maybe Natural.Natural,+ path :: Text.Text,+ projectId :: Text.Text+ }+ deriving (Eq, Show)++fromUri :: Catch.MonadThrow m => Uri.URI -> m Dsn+fromUri uri = do+ theProtocol <- maybe (Catch.throwM $ Problem.Problem "invalid scheme") pure . Text.stripSuffix (Text.singleton ':') . Text.pack $ Uri.uriScheme uri+ uriAuth <- maybe (Catch.throwM $ Problem.Problem "missing authority") pure $ Uri.uriAuthority uri+ userInfo <- maybe (Catch.throwM $ Problem.Problem "invalid user information") pure . Text.stripSuffix (Text.singleton '@') . Text.pack $ Uri.uriUserInfo uriAuth+ let (thePublicKey, theSecretKey) = fmap (Text.drop 1) $ Text.breakOn (Text.singleton ':') userInfo+ theHost = Text.pack $ Uri.uriRegName uriAuth+ maybePort <- case Text.stripPrefix (Text.singleton ':') . Text.pack $ Uri.uriPort uriAuth of+ Nothing -> pure Nothing+ Just text -> maybe (Catch.throwM $ Problem.Problem "invalid port") (pure . Just) . Read.readMaybe $ Text.unpack text+ let (thePath, theProjectId) = Text.breakOnEnd (Text.singleton '/') . Text.pack $ Uri.uriPath uri+ Monad.unless (null $ Uri.uriQuery uri) . Catch.throwM $ Problem.Problem "unexpected query"+ Monad.unless (null $ Uri.uriFragment uri) . Catch.throwM $ Problem.Problem "unexpected fragment"+ pure+ Dsn+ { protocol = theProtocol,+ publicKey = thePublicKey,+ secretKey = theSecretKey,+ host = theHost,+ port = maybePort,+ path = thePath,+ projectId = theProjectId+ }++intoUri :: Dsn -> Uri.URI+intoUri dsn =+ Uri.URI+ { Uri.uriScheme = mconcat [Text.unpack $ protocol dsn, ":"],+ Uri.uriAuthority =+ Just+ Uri.URIAuth+ { Uri.uriUserInfo =+ mconcat+ [ Text.unpack $ publicKey dsn,+ case secretKey dsn of+ x+ | Text.null x -> ""+ | otherwise -> mconcat [":", Text.unpack x],+ "@"+ ],+ Uri.uriRegName = Text.unpack $ host dsn,+ Uri.uriPort = case port dsn of+ Nothing -> ""+ Just x -> mconcat [":", show x]+ },+ Uri.uriPath =+ mconcat+ [ Text.unpack $ path dsn,+ Text.unpack $ projectId dsn+ ],+ Uri.uriQuery = "",+ Uri.uriFragment = ""+ }++intoAuthorization :: Dsn -> ByteString.ByteString+intoAuthorization dsn =+ Text.encodeUtf8+ . (Text.pack "Sentry " <>)+ . Text.intercalate (Text.singleton ',')+ $ Maybe.mapMaybe+ (\(k, v) -> if Text.null v then Nothing else Just (Text.pack k <> Text.singleton '=' <> v))+ [ ("sentry_version", Constant.sentryVersion),+ ("sentry_client", Constant.userAgent),+ ("sentry_key", publicKey dsn),+ ("sentry_secret", secretKey dsn)+ ]
+ source/library/Patrol/Type/ErrorType.hs view
@@ -0,0 +1,89 @@+module Patrol.Type.ErrorType where++import qualified Data.Aeson as Aeson++data ErrorType+ = ClockDrift+ | FetchGenericError+ | FetchInvalidEncoding+ | FetchInvalidHttpCode+ | FetchTimeout+ | FetchTooLarge+ | FutureTimestamp+ | InvalidAttribute+ | InvalidData+ | InvalidEnvironment+ | JsFetchTimeout+ | JsGenericFetchError+ | JsInvalidContent+ | JsInvalidHttpCode+ | JsInvalidSourceEncoding+ | JsInvalidSourcemap+ | JsInvalidSourcemapLocation+ | JsMissingSource+ | JsNoColumn+ | JsTooLarge+ | JsTooManyRemoteSources+ | MissingAttribute+ | NativeBadDsym+ | NativeInternalFailure+ | NativeMissingDsym+ | NativeMissingOptionallyBundledDsym+ | NativeMissingSymbol+ | NativeMissingSystemDsym+ | NativeNoCrashedThread+ | NativeSimulatorFrame+ | NativeSymbolicatorFailed+ | NativeUnknownImage+ | PastTimestamp+ | ProguardMissingLineno+ | ProguardMissingMapping+ | RestrictedIp+ | SecurityViolation+ | TooLargeForCache+ | UnknownError+ | ValueTooLong+ deriving (Eq, Show)++instance Aeson.ToJSON ErrorType where+ toJSON errorType = Aeson.toJSON $ case errorType of+ ClockDrift -> "clock_drift"+ FetchGenericError -> "fetch_generic_error"+ FetchInvalidEncoding -> "fetch_invalid_source_encoding"+ FetchInvalidHttpCode -> "fetch_invalid_http_code"+ FetchTimeout -> "fetch_timeout"+ FetchTooLarge -> "fetch_too_large"+ FutureTimestamp -> "future_timestamp"+ InvalidAttribute -> "invalid_attribute"+ InvalidData -> "invalid_data"+ InvalidEnvironment -> "invalid_environment"+ JsFetchTimeout -> "js_fetch_timeout"+ JsGenericFetchError -> "js_generic_fetch_error"+ JsInvalidContent -> "js_invalid_content"+ JsInvalidHttpCode -> "js_invalid_http_code"+ JsInvalidSourceEncoding -> "js_invalid_source_encoding"+ JsInvalidSourcemap -> "js_invalid_source"+ JsInvalidSourcemapLocation -> "js_invalid_sourcemap_location"+ JsMissingSource -> "js_no_source"+ JsNoColumn -> "js_no_column"+ JsTooLarge -> "js_too_large"+ JsTooManyRemoteSources -> "js_too_many_sources"+ MissingAttribute -> "missing_attribute"+ NativeBadDsym -> "native_bad_dsym"+ NativeInternalFailure -> "native_internal_failure"+ NativeMissingDsym -> "native_missing_dsym"+ NativeMissingOptionallyBundledDsym -> "native_optionally_bundled_dsym"+ NativeMissingSymbol -> "native_missing_symbol"+ NativeMissingSystemDsym -> "native_missing_system_dsym"+ NativeNoCrashedThread -> "native_no_crashed_thread"+ NativeSimulatorFrame -> "native_simulator_frame"+ NativeSymbolicatorFailed -> "native_symbolicator_failed"+ NativeUnknownImage -> "native_unknown_image"+ PastTimestamp -> "past_timestamp"+ ProguardMissingLineno -> "proguard_missing_lineno"+ ProguardMissingMapping -> "proguard_missing_mapping"+ RestrictedIp -> "restricted_ip"+ SecurityViolation -> "security_violation"+ TooLargeForCache -> "too_large_for_cache"+ UnknownError -> "unknown_error"+ ValueTooLong -> "value_too_long"
+ source/library/Patrol/Type/Event.hs view
@@ -0,0 +1,174 @@+module Patrol.Type.Event where++import qualified Control.Monad.Catch as Catch+import qualified Control.Monad.IO.Class as IO+import qualified Data.Aeson as Aeson+import qualified Data.ByteString.Lazy as LazyByteString+import qualified Data.Map as Map+import qualified Data.Text as Text+import qualified Data.Text.Encoding as Text+import qualified Data.Time as Time+import qualified Network.HTTP.Client as Client+import qualified Network.HTTP.Types as Http+import qualified Patrol.Constant as Constant+import qualified Patrol.Extra.Aeson as Aeson+import qualified Patrol.Extra.List as List+import qualified Patrol.Type.Breadcrumbs as Breadcrumbs+import qualified Patrol.Type.ClientSdkInfo as ClientSdkInfo+import qualified Patrol.Type.Context as Context+import qualified Patrol.Type.DebugMeta as DebugMeta+import qualified Patrol.Type.Dsn as Dsn+import qualified Patrol.Type.EventId as EventId+import qualified Patrol.Type.EventProcessingError as EventProcessingError+import qualified Patrol.Type.EventType as EventType+import qualified Patrol.Type.Exceptions as Exceptions+import qualified Patrol.Type.Level as Level+import qualified Patrol.Type.LogEntry as LogEntry+import qualified Patrol.Type.Platform as Platform+import qualified Patrol.Type.Request as Request+import qualified Patrol.Type.Threads as Threads+import qualified Patrol.Type.TransactionInfo as TransactionInfo+import qualified Patrol.Type.User as User++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#event>+data Event = Event+ { breadcrumbs :: Maybe Breadcrumbs.Breadcrumbs,+ contexts :: Map.Map Text.Text Context.Context,+ debugMeta :: Maybe DebugMeta.DebugMeta,+ dist :: Text.Text,+ environment :: Text.Text,+ errors :: [EventProcessingError.EventProcessingError],+ eventId :: EventId.EventId,+ exception :: Maybe Exceptions.Exceptions,+ extra :: Map.Map Text.Text Aeson.Value,+ fingerprint :: [Text.Text],+ level :: Maybe Level.Level,+ logentry :: Maybe LogEntry.LogEntry,+ logger :: Text.Text,+ modules :: Map.Map Text.Text Text.Text,+ platform :: Maybe Platform.Platform,+ release :: Text.Text,+ request :: Maybe Request.Request,+ sdk :: Maybe ClientSdkInfo.ClientSdkInfo,+ serverName :: Text.Text,+ tags :: Map.Map Text.Text Text.Text,+ threads :: Maybe Threads.Threads,+ timeSpent :: Maybe Time.NominalDiffTime,+ timestamp :: Maybe Time.UTCTime,+ transaction :: Text.Text,+ transactionInfo :: Maybe TransactionInfo.TransactionInfo,+ type_ :: Maybe EventType.EventType,+ user :: Maybe User.User,+ version :: Text.Text+ }+ deriving (Eq, Show)++instance Aeson.ToJSON Event where+ toJSON event =+ Aeson.intoObject+ [ Aeson.pair "breadcrumbs" $ breadcrumbs event,+ Aeson.pair "contexts" $ contexts event,+ Aeson.pair "debug_meta" $ debugMeta event,+ Aeson.pair "dist" $ dist event,+ Aeson.pair "environment" $ environment event,+ Aeson.pair "errors" $ errors event,+ Aeson.pair "exception" $ exception event,+ Aeson.pair "extra" $ extra event,+ Aeson.pair "event_id" $ eventId event,+ Aeson.pair "fingerprint" $ fingerprint event,+ Aeson.pair "level" $ level event,+ Aeson.pair "logentry" $ logentry event,+ Aeson.pair "logger" $ logger event,+ Aeson.pair "modules" $ modules event,+ Aeson.pair "platform" $ platform event,+ Aeson.pair "release" $ release event,+ Aeson.pair "request" $ request event,+ Aeson.pair "sdk" $ sdk event,+ Aeson.pair "server_name" $ serverName event,+ Aeson.pair "tags" $ tags event,+ Aeson.pair "threads" $ threads event,+ Aeson.pair "time_spent" $ timeSpent event,+ Aeson.pair "timestamp" $ timestamp event,+ Aeson.pair "transaction" $ transaction event,+ Aeson.pair "transaction_info" $ transactionInfo event,+ Aeson.pair "type" $ type_ event,+ Aeson.pair "user" $ user event,+ Aeson.pair "version" $ version event+ ]++empty :: Event+empty =+ Event+ { breadcrumbs = Nothing,+ contexts = Map.empty,+ debugMeta = Nothing,+ dist = Text.empty,+ environment = Text.empty,+ errors = [],+ eventId = EventId.empty,+ exception = Nothing,+ extra = Map.empty,+ fingerprint = [],+ level = Nothing,+ logentry = Nothing,+ logger = Text.empty,+ modules = Map.empty,+ platform = Nothing,+ release = Text.empty,+ request = Nothing,+ sdk = Nothing,+ serverName = Text.empty,+ tags = Map.empty,+ threads = Nothing,+ timeSpent = Nothing,+ timestamp = Nothing,+ transaction = Text.empty,+ transactionInfo = Nothing,+ type_ = Nothing,+ user = Nothing,+ version = Text.empty+ }++new :: IO.MonadIO io => io Event+new = do+ theEventId <- EventId.random+ theTimestamp <- IO.liftIO Time.getCurrentTime+ pure+ empty+ { environment = Text.pack "production",+ eventId = theEventId,+ level = Just Level.Error,+ platform = Just Platform.Haskell,+ timestamp = Just theTimestamp,+ type_ = Just EventType.Default,+ version = Constant.sentryVersion+ }++intoRequest :: Catch.MonadThrow m => Dsn.Dsn -> Event -> m Client.Request+intoRequest dsn event = do+ theRequest <-+ Client.parseUrlThrow+ . Text.unpack+ $ mconcat+ [ Dsn.protocol dsn,+ Text.pack "://",+ Dsn.host dsn,+ maybe Text.empty (Text.pack . (:) ':' . show) $ Dsn.port dsn,+ Dsn.path dsn,+ Text.pack "api/",+ Dsn.projectId dsn,+ Text.pack "/store/"+ ]+ let oldHeaders = Client.requestHeaders theRequest+ authorization = Dsn.intoAuthorization dsn+ newHeaders =+ [ (Http.hContentType, Constant.applicationJson),+ (Http.hUserAgent, Text.encodeUtf8 Constant.userAgent),+ (Constant.xSentryAuth, authorization)+ ]+ pure+ theRequest+ { Client.method = Http.methodPost,+ Client.requestBody = Client.RequestBodyBS . LazyByteString.toStrict $ Aeson.encode event,+ Client.requestHeaders = List.insertAll newHeaders oldHeaders+ }
+ source/library/Patrol/Type/EventId.hs view
@@ -0,0 +1,61 @@+module Patrol.Type.EventId where++import qualified Control.Monad as Monad+import qualified Control.Monad.Catch as Catch+import qualified Control.Monad.IO.Class as IO+import qualified Data.Aeson as Aeson+import qualified Data.Text as Text+import qualified Data.Text.Read as Text+import qualified Data.Typeable as Typeable+import qualified Data.UUID as Uuid+import qualified Data.UUID.V4 as Uuid+import qualified Patrol.Exception.Problem as Problem+import qualified Text.Printf as Printf++newtype EventId+ = EventId Uuid.UUID+ deriving (Eq, Show)++instance Aeson.FromJSON EventId where+ parseJSON =+ let name = show $ Typeable.typeRep (Typeable.Proxy :: Typeable.Proxy EventId)+ in Aeson.withText name $ maybe (fail $ "invalid " <> name) pure . fromText++instance Aeson.ToJSON EventId where+ toJSON = Aeson.toJSON . intoText++empty :: EventId+empty = fromUuid Uuid.nil++fromUuid :: Uuid.UUID -> EventId+fromUuid = EventId++intoUuid :: EventId -> Uuid.UUID+intoUuid (EventId uuid) = uuid++random :: IO.MonadIO io => io EventId+random = IO.liftIO $ fmap fromUuid Uuid.nextRandom++intoText :: EventId -> Text.Text+intoText eventId =+ let (lo, hi) = Uuid.toWords64 $ intoUuid eventId+ in Text.pack $ Printf.printf "%016x%016x" lo hi++fromText :: Catch.MonadThrow m => Text.Text -> m EventId+fromText t1 = do+ let parse :: (Catch.MonadThrow n, Integral a) => Int -> Text.Text -> n (a, Text.Text)+ parse size text = do+ let (before, after) = Text.splitAt size text+ case Text.compareLength before size of+ GT -> Catch.throwM $ Problem.Problem "impossible"+ LT -> Catch.throwM $ Problem.Problem "not enough input"+ EQ -> case Text.hexadecimal before of+ Left _ -> Catch.throwM $ Problem.Problem "invalid hexadecimal"+ Right (integral, leftover) ->+ if Text.null leftover+ then pure (integral, after)+ else Catch.throwM $ Problem.Problem "invalid hexadecimal"+ (lo, t2) <- parse 16 t1+ (hi, t3) <- parse 16 t2+ Monad.unless (Text.null t3) . Catch.throwM $ Problem.Problem "too much input"+ pure . fromUuid $ Uuid.fromWords64 lo hi
+ source/library/Patrol/Type/EventProcessingError.hs view
@@ -0,0 +1,30 @@+module Patrol.Type.EventProcessingError where++import qualified Data.Aeson as Aeson+import qualified Data.Text as Text+import qualified Patrol.Extra.Aeson as Aeson+import qualified Patrol.Type.ErrorType as ErrorType++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#eventprocessingerror>+data EventProcessingError = EventProcessingError+ { name :: Text.Text,+ type_ :: ErrorType.ErrorType,+ value :: Aeson.Value+ }+ deriving (Eq, Show)++instance Aeson.ToJSON EventProcessingError where+ toJSON eventProcessingError =+ Aeson.intoObject+ [ Aeson.pair "name" $ name eventProcessingError,+ Aeson.pair "type" $ type_ eventProcessingError,+ Aeson.pair "value" $ value eventProcessingError+ ]++empty :: EventProcessingError+empty =+ EventProcessingError+ { name = Text.empty,+ type_ = ErrorType.UnknownError,+ value = Aeson.Null+ }
+ source/library/Patrol/Type/EventType.hs view
@@ -0,0 +1,24 @@+module Patrol.Type.EventType where++import qualified Data.Aeson as Aeson++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#eventtype>+data EventType+ = Csp+ | Default+ | Error+ | Expectct+ | Expectstaple+ | Hpkp+ | Transaction+ deriving (Eq, Show)++instance Aeson.ToJSON EventType where+ toJSON eventType = Aeson.toJSON $ case eventType of+ Csp -> "csp"+ Default -> "default"+ Error -> "error"+ Expectct -> "expectct"+ Expectstaple -> "expectstaple"+ Hpkp -> "hpkp"+ Transaction -> "transaction"
+ source/library/Patrol/Type/Exception.hs view
@@ -0,0 +1,49 @@+module Patrol.Type.Exception where++import qualified Control.Monad.Catch as Catch+import qualified Data.Aeson as Aeson+import qualified Data.Text as Text+import qualified Data.Typeable as Typeable+import qualified Patrol.Extra.Aeson as Aeson+import qualified Patrol.Type.Mechanism as Mechanism+import qualified Patrol.Type.Stacktrace as Stacktrace++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#valueclass>+data Exception = Exception+ { mechanism :: Maybe Mechanism.Mechanism,+ module_ :: Text.Text,+ stacktrace :: Maybe Stacktrace.Stacktrace,+ threadId :: Text.Text,+ type_ :: Text.Text,+ value :: Text.Text+ }+ deriving (Eq, Show)++instance Aeson.ToJSON Exception where+ toJSON exception =+ Aeson.intoObject+ [ Aeson.pair "mechanism" $ mechanism exception,+ Aeson.pair "module" $ module_ exception,+ Aeson.pair "stacktrace" $ stacktrace exception,+ Aeson.pair "thread_id" $ threadId exception,+ Aeson.pair "type" $ type_ exception,+ Aeson.pair "value" $ value exception+ ]++empty :: Exception+empty =+ Exception+ { mechanism = Nothing,+ module_ = Text.empty,+ stacktrace = Nothing,+ threadId = Text.empty,+ type_ = Text.empty,+ value = Text.empty+ }++fromSomeException :: Catch.SomeException -> Exception+fromSomeException (Catch.SomeException e) =+ empty+ { type_ = Text.pack . show $ Typeable.typeOf e,+ value = Text.pack $ Catch.displayException e+ }
+ source/library/Patrol/Type/Exceptions.hs view
@@ -0,0 +1,23 @@+module Patrol.Type.Exceptions where++import qualified Data.Aeson as Aeson+import qualified Patrol.Extra.Aeson as Aeson+import qualified Patrol.Type.Exception as Exception++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#exception>+newtype Exceptions = Exceptions+ { values :: [Exception.Exception]+ }+ deriving (Eq, Show)++instance Aeson.ToJSON Exceptions where+ toJSON exceptions =+ Aeson.intoObject+ [ Aeson.pair "values" $ values exceptions+ ]++empty :: Exceptions+empty =+ Exceptions+ { values = []+ }
+ source/library/Patrol/Type/Frame.hs view
@@ -0,0 +1,90 @@+module Patrol.Type.Frame where++import qualified Data.Aeson as Aeson+import qualified Data.Map as Map+import qualified Data.Text as Text+import qualified GHC.Stack as Stack+import qualified Patrol.Extra.Aeson as Aeson+import qualified Patrol.Type.Platform as Platform++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#frame>+data Frame = Frame+ { absPath :: Text.Text,+ addrMode :: Text.Text,+ colno :: Maybe Int,+ contextLine :: Text.Text,+ filename :: Text.Text,+ function :: Text.Text,+ imageAddr :: Text.Text,+ inApp :: Maybe Bool,+ instructionAddr :: Text.Text,+ lineno :: Maybe Int,+ module_ :: Text.Text,+ package :: Text.Text,+ platform :: Maybe Platform.Platform,+ postContext :: [Text.Text],+ preContext :: [Text.Text],+ rawFunction :: Text.Text,+ stackStart :: Maybe Bool,+ symbolAddr :: Text.Text,+ vars :: Map.Map Text.Text Aeson.Value+ }+ deriving (Eq, Show)++instance Aeson.ToJSON Frame where+ toJSON frame =+ Aeson.intoObject+ [ Aeson.pair "abs_path" $ absPath frame,+ Aeson.pair "addr_mode" $ addrMode frame,+ Aeson.pair "colno" $ colno frame,+ Aeson.pair "context_line" $ contextLine frame,+ Aeson.pair "filename" $ filename frame,+ Aeson.pair "function" $ function frame,+ Aeson.pair "image_addr" $ imageAddr frame,+ Aeson.pair "in_app" $ inApp frame,+ Aeson.pair "instruction_addr" $ instructionAddr frame,+ Aeson.pair "lineno" $ lineno frame,+ Aeson.pair "module" $ module_ frame,+ Aeson.pair "package" $ package frame,+ Aeson.pair "platform" $ platform frame,+ Aeson.pair "post_context" $ postContext frame,+ Aeson.pair "pre_context" $ preContext frame,+ Aeson.pair "raw_function" $ rawFunction frame,+ Aeson.pair "stack_start" $ stackStart frame,+ Aeson.pair "symbol_addr" $ symbolAddr frame,+ Aeson.pair "vars" $ vars frame+ ]++empty :: Frame+empty =+ Frame+ { absPath = Text.empty,+ addrMode = Text.empty,+ colno = Nothing,+ contextLine = Text.empty,+ filename = Text.empty,+ function = Text.empty,+ imageAddr = Text.empty,+ inApp = Nothing,+ instructionAddr = Text.empty,+ lineno = Nothing,+ module_ = Text.empty,+ package = Text.empty,+ platform = Nothing,+ postContext = [],+ preContext = [],+ rawFunction = Text.empty,+ stackStart = Nothing,+ symbolAddr = Text.empty,+ vars = Map.empty+ }++fromSrcLoc :: Stack.SrcLoc -> Frame+fromSrcLoc srcLoc =+ empty+ { colno = Just $ Stack.srcLocStartCol srcLoc,+ filename = Text.pack $ Stack.srcLocFile srcLoc,+ lineno = Just $ Stack.srcLocStartLine srcLoc,+ module_ = Text.pack $ Stack.srcLocModule srcLoc,+ package = Text.pack $ Stack.srcLocPackage srcLoc+ }
+ source/library/Patrol/Type/Geo.hs view
@@ -0,0 +1,29 @@+module Patrol.Type.Geo where++import qualified Data.Aeson as Aeson+import qualified Data.Text as Text+import qualified Patrol.Extra.Aeson as Aeson++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#geo>+data Geo = Geo+ { city :: Text.Text,+ countryCode :: Text.Text,+ region :: Text.Text+ }+ deriving (Eq, Show)++instance Aeson.ToJSON Geo where+ toJSON geo =+ Aeson.intoObject+ [ Aeson.pair "city" $ city geo,+ Aeson.pair "country_code" $ countryCode geo,+ Aeson.pair "region" $ region geo+ ]++empty :: Geo+empty =+ Geo+ { city = Text.empty,+ countryCode = Text.empty,+ region = Text.empty+ }
+ source/library/Patrol/Type/GpuContext.hs view
@@ -0,0 +1,62 @@+module Patrol.Type.GpuContext where++import qualified Data.Aeson as Aeson+import qualified Data.Text as Text+import qualified Patrol.Extra.Aeson as Aeson++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#gpucontext>+data GpuContext = GpuContext+ { apiType :: Text.Text,+ graphicsShaderLevel :: Text.Text,+ id :: Aeson.Value,+ maxTextureSize :: Maybe Int,+ memorySize :: Maybe Double,+ multiThreadedRendering :: Maybe Bool,+ name :: Text.Text,+ npotSupport :: Text.Text,+ supportsComputeShaders :: Maybe Bool,+ supportsGeometryShaders :: Maybe Bool,+ supportsRayTracing :: Maybe Bool,+ vendorId :: Text.Text,+ vendorName :: Text.Text,+ version :: Text.Text+ }+ deriving (Eq, Show)++instance Aeson.ToJSON GpuContext where+ toJSON gpuContext =+ Aeson.intoObject+ [ Aeson.pair "api_type" $ apiType gpuContext,+ Aeson.pair "graphics_shader_level" $ graphicsShaderLevel gpuContext,+ Aeson.pair "id" $ Patrol.Type.GpuContext.id gpuContext,+ Aeson.pair "max_texture_size" $ maxTextureSize gpuContext,+ Aeson.pair "memory_size" $ memorySize gpuContext,+ Aeson.pair "multi_threaded_rendering" $ multiThreadedRendering gpuContext,+ Aeson.pair "name" $ name gpuContext,+ Aeson.pair "npot_support" $ npotSupport gpuContext,+ Aeson.pair "supports_compute_shaders" $ supportsComputeShaders gpuContext,+ Aeson.pair "supports_geometry_shaders" $ supportsGeometryShaders gpuContext,+ Aeson.pair "supports_ray_tracing" $ supportsRayTracing gpuContext,+ Aeson.pair "vendor_id" $ vendorId gpuContext,+ Aeson.pair "vendor_name" $ vendorName gpuContext,+ Aeson.pair "version" $ version gpuContext+ ]++empty :: GpuContext+empty =+ GpuContext+ { apiType = Text.empty,+ graphicsShaderLevel = Text.empty,+ Patrol.Type.GpuContext.id = Aeson.Null,+ maxTextureSize = Nothing,+ memorySize = Nothing,+ multiThreadedRendering = Nothing,+ name = Text.empty,+ npotSupport = Text.empty,+ supportsComputeShaders = Nothing,+ supportsGeometryShaders = Nothing,+ supportsRayTracing = Nothing,+ vendorId = Text.empty,+ vendorName = Text.empty,+ version = Text.empty+ }
+ source/library/Patrol/Type/Level.hs view
@@ -0,0 +1,20 @@+module Patrol.Type.Level where++import qualified Data.Aeson as Aeson++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#level>+data Level+ = Debug+ | Info+ | Warning+ | Error+ | Fatal+ deriving (Eq, Show)++instance Aeson.ToJSON Level where+ toJSON level = Aeson.toJSON $ case level of+ Debug -> "debug"+ Info -> "info"+ Warning -> "warning"+ Error -> "error"+ Fatal -> "fatal"
+ source/library/Patrol/Type/LogEntry.hs view
@@ -0,0 +1,29 @@+module Patrol.Type.LogEntry where++import qualified Data.Aeson as Aeson+import qualified Data.Text as Text+import qualified Patrol.Extra.Aeson as Aeson++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#logentry>+data LogEntry = LogEntry+ { formatted :: Text.Text,+ message :: Text.Text,+ params :: Aeson.Value+ }+ deriving (Eq, Show)++instance Aeson.ToJSON LogEntry where+ toJSON logEntry =+ Aeson.intoObject+ [ Aeson.pair "formatted" $ formatted logEntry,+ Aeson.pair "message" $ message logEntry,+ Aeson.pair "params" $ params logEntry+ ]++empty :: LogEntry+empty =+ LogEntry+ { formatted = Text.empty,+ message = Text.empty,+ params = Aeson.Null+ }
+ source/library/Patrol/Type/MachException.hs view
@@ -0,0 +1,32 @@+module Patrol.Type.MachException where++import qualified Data.Aeson as Aeson+import qualified Data.Text as Text+import qualified Patrol.Extra.Aeson as Aeson++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#machexception>+data MachException = MachException+ { code :: Maybe Int,+ exception :: Maybe Int,+ name :: Text.Text,+ subcode :: Maybe Int+ }+ deriving (Eq, Show)++instance Aeson.ToJSON MachException where+ toJSON machException =+ Aeson.intoObject+ [ Aeson.pair "code" $ code machException,+ Aeson.pair "exception" $ exception machException,+ Aeson.pair "name" $ name machException,+ Aeson.pair "subcode" $ subcode machException+ ]++empty :: MachException+empty =+ MachException+ { code = Nothing,+ exception = Nothing,+ name = Text.empty,+ subcode = Nothing+ }
+ source/library/Patrol/Type/Mechanism.hs view
@@ -0,0 +1,43 @@+module Patrol.Type.Mechanism where++import qualified Data.Aeson as Aeson+import qualified Data.Map as Map+import qualified Data.Text as Text+import qualified Patrol.Extra.Aeson as Aeson+import qualified Patrol.Type.MechanismMeta as MechanismMeta++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#mechanism>+data Mechanism = Mechanism+ { data_ :: Map.Map Text.Text Aeson.Value,+ description :: Text.Text,+ handled :: Maybe Bool,+ helpLink :: Text.Text,+ meta :: Maybe MechanismMeta.MechanismMeta,+ synthetic :: Maybe Bool,+ type_ :: Text.Text+ }+ deriving (Eq, Show)++instance Aeson.ToJSON Mechanism where+ toJSON mechanism =+ Aeson.intoObject+ [ Aeson.pair "data" $ data_ mechanism,+ Aeson.pair "description" $ description mechanism,+ Aeson.pair "handled" $ handled mechanism,+ Aeson.pair "help_link" $ helpLink mechanism,+ Aeson.pair "meta" $ meta mechanism,+ Aeson.pair "synthetic" $ synthetic mechanism,+ Aeson.pair "type" $ type_ mechanism+ ]++empty :: Mechanism+empty =+ Mechanism+ { data_ = Map.empty,+ description = Text.empty,+ handled = Nothing,+ helpLink = Text.empty,+ meta = Nothing,+ synthetic = Nothing,+ type_ = Text.empty+ }
+ source/library/Patrol/Type/MechanismMeta.hs view
@@ -0,0 +1,35 @@+module Patrol.Type.MechanismMeta where++import qualified Data.Aeson as Aeson+import qualified Patrol.Extra.Aeson as Aeson+import qualified Patrol.Type.CError as CError+import qualified Patrol.Type.MachException as MachException+import qualified Patrol.Type.NsError as NsError+import qualified Patrol.Type.PosixSignal as PosixSignal++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#mechanismmeta>+data MechanismMeta = MechanismMeta+ { errno :: Maybe CError.CError,+ machException :: Maybe MachException.MachException,+ nsError :: Maybe NsError.NsError,+ signal :: Maybe PosixSignal.PosixSignal+ }+ deriving (Eq, Show)++instance Aeson.ToJSON MechanismMeta where+ toJSON mechanismMeta =+ Aeson.intoObject+ [ Aeson.pair "errno" $ errno mechanismMeta,+ Aeson.pair "mach_exception" $ machException mechanismMeta,+ Aeson.pair "ns_error" $ nsError mechanismMeta,+ Aeson.pair "signal" $ signal mechanismMeta+ ]++empty :: MechanismMeta+empty =+ MechanismMeta+ { errno = Nothing,+ machException = Nothing,+ nsError = Nothing,+ signal = Nothing+ }
+ source/library/Patrol/Type/NativeDebugImage.hs view
@@ -0,0 +1,47 @@+module Patrol.Type.NativeDebugImage where++import qualified Data.Aeson as Aeson+import qualified Data.Text as Text+import qualified Patrol.Extra.Aeson as Aeson++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#nativedebugimage>+data NativeDebugImage = NativeDebugImage+ { arch :: Text.Text,+ codeFile :: Text.Text,+ codeId :: Text.Text,+ debugFile :: Text.Text,+ debugId :: Text.Text,+ imageAddr :: Text.Text,+ imageSize :: Maybe Int,+ imageVmaddr :: Text.Text,+ type_ :: Text.Text+ }+ deriving (Eq, Show)++instance Aeson.ToJSON NativeDebugImage where+ toJSON nativeDebugImage =+ Aeson.intoObject+ [ Aeson.pair "arch" $ arch nativeDebugImage,+ Aeson.pair "code_file" $ codeFile nativeDebugImage,+ Aeson.pair "code_id" $ codeId nativeDebugImage,+ Aeson.pair "debug_file" $ debugFile nativeDebugImage,+ Aeson.pair "debug_id" $ debugId nativeDebugImage,+ Aeson.pair "image_addr" $ imageAddr nativeDebugImage,+ Aeson.pair "image_size" $ imageSize nativeDebugImage,+ Aeson.pair "image_vmaddr" $ imageVmaddr nativeDebugImage,+ Aeson.pair "type" $ type_ nativeDebugImage+ ]++empty :: NativeDebugImage+empty =+ NativeDebugImage+ { arch = Text.empty,+ codeFile = Text.empty,+ codeId = Text.empty,+ debugFile = Text.empty,+ debugId = Text.empty,+ imageAddr = Text.empty,+ imageSize = Nothing,+ imageVmaddr = Text.empty,+ type_ = Text.empty+ }
+ source/library/Patrol/Type/NsError.hs view
@@ -0,0 +1,26 @@+module Patrol.Type.NsError where++import qualified Data.Aeson as Aeson+import qualified Data.Text as Text+import qualified Patrol.Extra.Aeson as Aeson++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#nserror>+data NsError = NsError+ { code :: Maybe Int,+ domain :: Text.Text+ }+ deriving (Eq, Show)++instance Aeson.ToJSON NsError where+ toJSON nsError =+ Aeson.intoObject+ [ Aeson.pair "code" $ code nsError,+ Aeson.pair "domain" $ domain nsError+ ]++empty :: NsError+empty =+ NsError+ { code = Nothing,+ domain = Text.empty+ }
+ source/library/Patrol/Type/OsContext.hs view
@@ -0,0 +1,38 @@+module Patrol.Type.OsContext where++import qualified Data.Aeson as Aeson+import qualified Data.Text as Text+import qualified Patrol.Extra.Aeson as Aeson++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#oscontext>+data OsContext = OsContext+ { build :: Text.Text,+ kernelVersion :: Text.Text,+ name :: Text.Text,+ rawDescription :: Text.Text,+ rooted :: Maybe Bool,+ version :: Text.Text+ }+ deriving (Eq, Show)++instance Aeson.ToJSON OsContext where+ toJSON osContext =+ Aeson.intoObject+ [ Aeson.pair "build" $ build osContext,+ Aeson.pair "kernel_version" $ kernelVersion osContext,+ Aeson.pair "name" $ name osContext,+ Aeson.pair "raw_description" $ rawDescription osContext,+ Aeson.pair "rooted" $ rooted osContext,+ Aeson.pair "version" $ version osContext+ ]++empty :: OsContext+empty =+ OsContext+ { build = Text.empty,+ kernelVersion = Text.empty,+ name = Text.empty,+ rawDescription = Text.empty,+ rooted = Nothing,+ version = Text.empty+ }
+ source/library/Patrol/Type/Platform.hs view
@@ -0,0 +1,47 @@+module Patrol.Type.Platform where++import qualified Data.Aeson as Aeson++data Platform+ = As3+ | C+ | Cfml+ | Cocoa+ | Csharp+ | Elixir+ | Haskell+ | Go+ | Groovy+ | Java+ | Javascript+ | Native+ | Node+ | Objc+ | Other+ | Perl+ | Php+ | Python+ | Ruby+ deriving (Eq, Show)++instance Aeson.ToJSON Platform where+ toJSON platform = Aeson.toJSON $ case platform of+ As3 -> "as3"+ C -> "c"+ Cfml -> "cfml"+ Cocoa -> "cocoa"+ Csharp -> "csharp"+ Elixir -> "elixir"+ Haskell -> "haskell"+ Go -> "go"+ Groovy -> "groovy"+ Java -> "java"+ Javascript -> "javascript"+ Native -> "native"+ Node -> "node"+ Objc -> "objc"+ Other -> "other"+ Perl -> "perl"+ Php -> "php"+ Python -> "python"+ Ruby -> "ruby"
+ source/library/Patrol/Type/PosixSignal.hs view
@@ -0,0 +1,32 @@+module Patrol.Type.PosixSignal where++import qualified Data.Aeson as Aeson+import qualified Data.Text as Text+import qualified Patrol.Extra.Aeson as Aeson++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#posixsignal>+data PosixSignal = PosixSignal+ { code :: Maybe Int,+ codeName :: Text.Text,+ name :: Text.Text,+ number :: Maybe Int+ }+ deriving (Eq, Show)++instance Aeson.ToJSON PosixSignal where+ toJSON posixSignal =+ Aeson.intoObject+ [ Aeson.pair "code" $ code posixSignal,+ Aeson.pair "code_name" $ codeName posixSignal,+ Aeson.pair "name" $ name posixSignal,+ Aeson.pair "number" $ number posixSignal+ ]++empty :: PosixSignal+empty =+ PosixSignal+ { code = Nothing,+ codeName = Text.empty,+ name = Text.empty,+ number = Nothing+ }
+ source/library/Patrol/Type/ProguardDebugImage.hs view
@@ -0,0 +1,23 @@+module Patrol.Type.ProguardDebugImage where++import qualified Data.Aeson as Aeson+import qualified Data.Text as Text+import qualified Patrol.Extra.Aeson as Aeson++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#proguarddebugimage>+newtype ProguardDebugImage = ProguardDebugImage+ { uuid :: Text.Text+ }+ deriving (Eq, Show)++instance Aeson.ToJSON ProguardDebugImage where+ toJSON proguardDebugImage =+ Aeson.intoObject+ [ Aeson.pair "uuid" $ uuid proguardDebugImage+ ]++empty :: ProguardDebugImage+empty =+ ProguardDebugImage+ { uuid = Text.empty+ }
+ source/library/Patrol/Type/Request.hs view
@@ -0,0 +1,48 @@+module Patrol.Type.Request where++import qualified Data.Aeson as Aeson+import qualified Data.Map as Map+import qualified Data.Text as Text+import qualified Patrol.Extra.Aeson as Aeson++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#request>+data Request = Request+ { cookies :: Map.Map Text.Text Text.Text,+ data_ :: Aeson.Value,+ env :: Map.Map Text.Text Aeson.Value,+ fragment :: Text.Text,+ headers :: Map.Map Text.Text Text.Text,+ inferredContentType :: Text.Text,+ method :: Text.Text,+ queryString :: Map.Map Text.Text Text.Text,+ url :: Text.Text+ }+ deriving (Eq, Show)++instance Aeson.ToJSON Request where+ toJSON request =+ Aeson.intoObject+ [ Aeson.pair "cookies" $ cookies request,+ Aeson.pair "data" $ data_ request,+ Aeson.pair "env" $ env request,+ Aeson.pair "fragment" $ fragment request,+ Aeson.pair "headers" $ headers request,+ Aeson.pair "inferred_content_type" $ inferredContentType request,+ Aeson.pair "method" $ method request,+ Aeson.pair "query_string" $ queryString request,+ Aeson.pair "url" $ url request+ ]++empty :: Request+empty =+ Request+ { cookies = Map.empty,+ data_ = Aeson.Null,+ env = Map.empty,+ fragment = Text.empty,+ headers = Map.empty,+ inferredContentType = Text.empty,+ method = Text.empty,+ queryString = Map.empty,+ url = Text.empty+ }
+ source/library/Patrol/Type/Response.hs view
@@ -0,0 +1,21 @@+module Patrol.Type.Response where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.Key as Key+import qualified Data.Typeable as Typeable+import qualified Patrol.Type.EventId as EventId++newtype Response = Response+ { id :: EventId.EventId+ }+ deriving (Eq, Show)++instance Aeson.FromJSON Response where+ parseJSON =+ let name = show $ Typeable.typeRep (Typeable.Proxy :: Typeable.Proxy Response)+ in Aeson.withObject name $ \object -> do+ theId <- object Aeson..: Key.fromString "id"+ pure+ Response+ { Patrol.Type.Response.id = theId+ }
+ source/library/Patrol/Type/RuntimeContext.hs view
@@ -0,0 +1,32 @@+module Patrol.Type.RuntimeContext where++import qualified Data.Aeson as Aeson+import qualified Data.Text as Text+import qualified Patrol.Extra.Aeson as Aeson++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#runtimecontext>+data RuntimeContext = RuntimeContext+ { build :: Text.Text,+ name :: Text.Text,+ rawDescription :: Text.Text,+ version :: Text.Text+ }+ deriving (Eq, Show)++instance Aeson.ToJSON RuntimeContext where+ toJSON runtimeContext =+ Aeson.intoObject+ [ Aeson.pair "build" $ build runtimeContext,+ Aeson.pair "name" $ name runtimeContext,+ Aeson.pair "raw_description" $ rawDescription runtimeContext,+ Aeson.pair "version" $ version runtimeContext+ ]++empty :: RuntimeContext+empty =+ RuntimeContext+ { build = Text.empty,+ name = Text.empty,+ rawDescription = Text.empty,+ version = Text.empty+ }
+ source/library/Patrol/Type/SpanStatus.hs view
@@ -0,0 +1,44 @@+module Patrol.Type.SpanStatus where++import qualified Data.Aeson as Aeson++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#spanstatus>+data SpanStatus+ = Aborted+ | AlreadyExists+ | Cancelled+ | DataLoss+ | DeadlineExceeded+ | FailedPrecondition+ | InternalError+ | InvalidArgument+ | NotFound+ | Ok+ | OutOfRange+ | PermissionDenied+ | ResourceExhausted+ | Unauthenticated+ | Unavailable+ | Unimplemented+ | Unknown+ deriving (Eq, Show)++instance Aeson.ToJSON SpanStatus where+ toJSON spanStatus = Aeson.toJSON $ case spanStatus of+ Aborted -> "aborted"+ AlreadyExists -> "already_exists"+ Cancelled -> "cancelled"+ DataLoss -> "data_loss"+ DeadlineExceeded -> "deadline_exceeded"+ FailedPrecondition -> "failed_precondition"+ InternalError -> "internal_error"+ InvalidArgument -> "invalid_argument"+ NotFound -> "not_found"+ Ok -> "ok"+ OutOfRange -> "out_of_range"+ PermissionDenied -> "permission_denied"+ ResourceExhausted -> "resource_exhausted"+ Unauthenticated -> "unauthenticated"+ Unavailable -> "unavailable"+ Unimplemented -> "unimplemented"+ Unknown -> "unknown"
+ source/library/Patrol/Type/Stacktrace.hs view
@@ -0,0 +1,37 @@+module Patrol.Type.Stacktrace where++import qualified Data.Aeson as Aeson+import qualified Data.Map as Map+import qualified Data.Text as Text+import qualified GHC.Stack as Stack+import qualified Patrol.Extra.Aeson as Aeson+import qualified Patrol.Type.Frame as Frame++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#stacktrace>+data Stacktrace = Stacktrace+ { frames :: [Frame.Frame],+ registers :: Map.Map Text.Text Text.Text+ }+ deriving (Eq, Show)++instance Aeson.ToJSON Stacktrace where+ toJSON stacktrace =+ Aeson.intoObject+ [ Aeson.pair "frames" $ frames stacktrace,+ Aeson.pair "registers" $ registers stacktrace+ ]++empty :: Stacktrace+empty =+ Stacktrace+ { frames = [],+ registers = Map.empty+ }++fromCallStack :: Stack.CallStack -> Stacktrace+fromCallStack =+ let intoFrame string srcLoc =+ (Frame.fromSrcLoc srcLoc)+ { Frame.function = Text.pack string+ }+ in flip Stacktrace Map.empty . fmap (uncurry intoFrame) . reverse . Stack.getCallStack
+ source/library/Patrol/Type/SystemSdkInfo.hs view
@@ -0,0 +1,32 @@+module Patrol.Type.SystemSdkInfo where++import qualified Data.Aeson as Aeson+import qualified Data.Text as Text+import qualified Patrol.Extra.Aeson as Aeson++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#systemsdkinfo>+data SystemSdkInfo = SystemSdkInfo+ { sdkName :: Text.Text,+ versionMajor :: Maybe Int,+ versionMinor :: Maybe Int,+ versionPatchlevel :: Maybe Int+ }+ deriving (Eq, Show)++instance Aeson.ToJSON SystemSdkInfo where+ toJSON systemSdkInfo =+ Aeson.intoObject+ [ Aeson.pair "sdk_name" $ sdkName systemSdkInfo,+ Aeson.pair "version_major" $ versionMajor systemSdkInfo,+ Aeson.pair "version_minor" $ versionMinor systemSdkInfo,+ Aeson.pair "version_patchlevel" $ versionPatchlevel systemSdkInfo+ ]++empty :: SystemSdkInfo+empty =+ SystemSdkInfo+ { sdkName = Text.empty,+ versionMajor = Nothing,+ versionMinor = Nothing,+ versionPatchlevel = Nothing+ }
+ source/library/Patrol/Type/Thread.hs view
@@ -0,0 +1,36 @@+module Patrol.Type.Thread where++import qualified Data.Aeson as Aeson+import qualified Data.Text as Text+import qualified Patrol.Extra.Aeson as Aeson+import qualified Patrol.Type.Stacktrace as Stacktrace++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#thread>+data Thread = Thread+ { crashed :: Maybe Bool,+ current :: Maybe Bool,+ id :: Text.Text,+ name :: Text.Text,+ stacktrace :: Maybe Stacktrace.Stacktrace+ }+ deriving (Eq, Show)++instance Aeson.ToJSON Thread where+ toJSON thread =+ Aeson.intoObject+ [ Aeson.pair "crashed" $ crashed thread,+ Aeson.pair "current" $ current thread,+ Aeson.pair "id" $ Patrol.Type.Thread.id thread,+ Aeson.pair "name" $ name thread,+ Aeson.pair "stacktrace" $ stacktrace thread+ ]++empty :: Thread+empty =+ Thread+ { crashed = Nothing,+ current = Nothing,+ Patrol.Type.Thread.id = Text.empty,+ name = Text.empty,+ stacktrace = Nothing+ }
+ source/library/Patrol/Type/Threads.hs view
@@ -0,0 +1,23 @@+module Patrol.Type.Threads where++import qualified Data.Aeson as Aeson+import qualified Patrol.Extra.Aeson as Aeson+import qualified Patrol.Type.Thread as Thread++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#threads>+newtype Threads = Threads+ { values :: [Thread.Thread]+ }+ deriving (Eq, Show)++instance Aeson.ToJSON Threads where+ toJSON threads =+ Aeson.intoObject+ [ Aeson.pair "values" $ values threads+ ]++empty :: Threads+empty =+ Threads+ { values = []+ }
+ source/library/Patrol/Type/TraceContext.hs view
@@ -0,0 +1,39 @@+module Patrol.Type.TraceContext where++import qualified Data.Aeson as Aeson+import qualified Data.Text as Text+import qualified Patrol.Extra.Aeson as Aeson+import qualified Patrol.Type.SpanStatus as SpanStatus++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#tracecontext>+data TraceContext = TraceContext+ { exclusiveTime :: Maybe Int,+ op :: Text.Text,+ parentSpanId :: Text.Text,+ spanId :: Text.Text,+ status :: Maybe SpanStatus.SpanStatus,+ traceId :: Text.Text+ }+ deriving (Eq, Show)++instance Aeson.ToJSON TraceContext where+ toJSON traceContext =+ Aeson.intoObject+ [ Aeson.pair "exclusive_time" $ exclusiveTime traceContext,+ Aeson.pair "op" $ op traceContext,+ Aeson.pair "parent_span_id" $ parentSpanId traceContext,+ Aeson.pair "span_id" $ spanId traceContext,+ Aeson.pair "status" $ status traceContext,+ Aeson.pair "trace_id" $ traceId traceContext+ ]++empty :: TraceContext+empty =+ TraceContext+ { exclusiveTime = Nothing,+ op = Text.empty,+ parentSpanId = Text.empty,+ spanId = Text.empty,+ status = Nothing,+ traceId = Text.empty+ }
+ source/library/Patrol/Type/TransactionInfo.hs view
@@ -0,0 +1,27 @@+module Patrol.Type.TransactionInfo where++import qualified Data.Aeson as Aeson+import qualified Data.Text as Text+import qualified Patrol.Extra.Aeson as Aeson+import qualified Patrol.Type.TransactionSource as TransactionSource++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#transactioninfo>+data TransactionInfo = TransactionInfo+ { original :: Text.Text,+ source :: Maybe TransactionSource.TransactionSource+ }+ deriving (Eq, Show)++instance Aeson.ToJSON TransactionInfo where+ toJSON transactionInfo =+ Aeson.intoObject+ [ Aeson.pair "original" $ original transactionInfo,+ Aeson.pair "source" $ source transactionInfo+ ]++empty :: TransactionInfo+empty =+ TransactionInfo+ { original = Text.empty,+ source = Nothing+ }
+ source/library/Patrol/Type/TransactionSource.hs view
@@ -0,0 +1,24 @@+module Patrol.Type.TransactionSource where++import qualified Data.Aeson as Aeson++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#transactionsource>+data TransactionSource+ = Component+ | Custom+ | Route+ | Task+ | Url+ | Unknown+ | View+ deriving (Eq, Show)++instance Aeson.ToJSON TransactionSource where+ toJSON transactionSource = Aeson.toJSON $ case transactionSource of+ Component -> "component"+ Custom -> "custom"+ Route -> "route"+ Task -> "task"+ Url -> "url"+ Unknown -> "unknown"+ View -> "view"
+ source/library/Patrol/Type/User.hs view
@@ -0,0 +1,46 @@+module Patrol.Type.User where++import qualified Data.Aeson as Aeson+import qualified Data.Map as Map+import qualified Data.Text as Text+import qualified Patrol.Extra.Aeson as Aeson+import qualified Patrol.Type.Geo as Geo++-- | <https://develop.sentry.dev/sdk/event-payloads/types/#user>+data User = User+ { data_ :: Map.Map Text.Text Aeson.Value,+ email :: Text.Text,+ geo :: Maybe Geo.Geo,+ id :: Text.Text,+ ipAddress :: Text.Text,+ name :: Text.Text,+ segment :: Text.Text,+ username :: Text.Text+ }+ deriving (Eq, Show)++instance Aeson.ToJSON User where+ toJSON user =+ Aeson.intoObject+ [ Aeson.pair "data" $ data_ user,+ Aeson.pair "email" $ email user,+ Aeson.pair "geo" $ geo user,+ Aeson.pair "id" $ Patrol.Type.User.id user,+ Aeson.pair "ip_address" $ ipAddress user,+ Aeson.pair "name" $ name user,+ Aeson.pair "segment" $ segment user,+ Aeson.pair "username" $ username user+ ]++empty :: User+empty =+ User+ { data_ = Map.empty,+ email = Text.empty,+ geo = Nothing,+ Patrol.Type.User.id = Text.empty,+ ipAddress = Text.empty,+ name = Text.empty,+ segment = Text.empty,+ username = Text.empty+ }
+ source/library/Patrol/Version.hs view
@@ -0,0 +1,14 @@+module Patrol.Version where++import qualified Data.Text as Text+import qualified Data.Version as Version+import qualified Paths_patrol as Package++string :: String+string = Version.showVersion version++text :: Text.Text+text = Text.pack string++version :: Version.Version+version = Package.version
+ source/test-suite/Main.hs view
@@ -0,0 +1,5 @@+import qualified PatrolSpec+import qualified Test.Hspec as Hspec++main :: IO ()+main = Hspec.hspec $ Hspec.parallel PatrolSpec.spec
+ source/test-suite/Patrol/ClientSpec.hs view
@@ -0,0 +1,8 @@+module Patrol.ClientSpec where++import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Client" $ do+ Hspec.it "needs tests" $ do+ Hspec.pending
+ source/test-suite/Patrol/ConstantSpec.hs view
@@ -0,0 +1,25 @@+module Patrol.ConstantSpec where++import qualified Data.CaseInsensitive as CI+import qualified Data.Text as Text+import qualified Data.Text.Encoding as Text+import qualified Patrol.Constant as Constant+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Constant" $ do+ Hspec.describe "applicationJson" $ do+ Hspec.it "is correct" $ do+ Constant.applicationJson `Hspec.shouldBe` Text.encodeUtf8 (Text.pack "application/json")++ Hspec.describe "sentryVersion" $ do+ Hspec.it "is correct" $ do+ Constant.sentryVersion `Hspec.shouldBe` Text.singleton '7'++ Hspec.describe "userAgent" $ do+ Hspec.it "is correct" $ do+ Constant.userAgent `Hspec.shouldSatisfy` Text.isPrefixOf (Text.pack "patrol/")++ Hspec.describe "xSentryAuth" $ do+ Hspec.it "is correct" $ do+ Constant.xSentryAuth `Hspec.shouldBe` CI.mk (Text.encodeUtf8 $ Text.pack "X-Sentry-Auth")
+ source/test-suite/Patrol/Extra/AesonSpec.hs view
@@ -0,0 +1,57 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Extra.AesonSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.Key as Key+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Map as Map+import qualified Patrol.Extra.Aeson as Extra+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Extra.Aeson" $ do+ Hspec.describe "intoObject" $ do+ Hspec.it "works with an empty object" $ do+ Extra.intoObject [] `Hspec.shouldBe` [Aeson.aesonQQ| {} |]++ Hspec.it "strips null" $ do+ Extra.intoObject [Extra.pair "k" Aeson.Null] `Hspec.shouldBe` [Aeson.aesonQQ| {} |]++ Hspec.it "does not strip false" $ do+ Extra.intoObject [Extra.pair "k" False] `Hspec.shouldBe` [Aeson.aesonQQ| { "k": false } |]++ Hspec.it "does not strip zero" $ do+ Extra.intoObject [Extra.pair "k" (0 :: Int)] `Hspec.shouldBe` [Aeson.aesonQQ| { "k": 0 } |]++ Hspec.it "strips empty string" $ do+ Extra.intoObject [Extra.pair "k" ""] `Hspec.shouldBe` [Aeson.aesonQQ| {} |]++ Hspec.it "strips empty array" $ do+ Extra.intoObject [Extra.pair "k" (mempty :: [Int])] `Hspec.shouldBe` [Aeson.aesonQQ| {} |]++ Hspec.it "strips empty object" $ do+ Extra.intoObject [Extra.pair "k" (mempty :: Map.Map String Int)] `Hspec.shouldBe` [Aeson.aesonQQ| {} |]++ Hspec.describe "isEmpty" $ do+ Hspec.it "is true for null" $ do+ Aeson.Null `Hspec.shouldSatisfy` Extra.isEmpty++ Hspec.it "is false for false" $ do+ Aeson.Bool False `Hspec.shouldNotSatisfy` Extra.isEmpty++ Hspec.it "is false for zero" $ do+ Aeson.Number 0 `Hspec.shouldNotSatisfy` Extra.isEmpty++ Hspec.it "is true for an empty string" $ do+ Aeson.String mempty `Hspec.shouldSatisfy` Extra.isEmpty++ Hspec.it "is true for an empty array" $ do+ Aeson.Array mempty `Hspec.shouldSatisfy` Extra.isEmpty++ Hspec.it "is true for an empty object" $ do+ Aeson.Object mempty `Hspec.shouldSatisfy` Extra.isEmpty++ Hspec.describe "pair" $ do+ Hspec.it "works" $ do+ Extra.pair "key" False `Hspec.shouldBe` (Key.fromString "key", Aeson.Bool False)
+ source/test-suite/Patrol/Extra/ListSpec.hs view
@@ -0,0 +1,59 @@+module Patrol.Extra.ListSpec where++import qualified Data.Char as Char+import qualified Data.Function as Function+import qualified Patrol.Extra.List as Extra+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Extra.List" $ do+ Hspec.describe "insertAll" $ do+ Hspec.it "handles empty lists" $ do+ Extra.insertAll [] [] `Hspec.shouldBe` ([] :: [(Char, Bool)])++ Hspec.it "inserts into an empty list" $ do+ Extra.insertAll [('a', False)] [] `Hspec.shouldBe` [('a', False)]++ Hspec.it "handles an empty list of insertions" $ do+ Extra.insertAll [] [('a', True)] `Hspec.shouldBe` [('a', True)]++ Hspec.it "prefers the original element" $ do+ Extra.insertAll [('a', False)] [('a', True)] `Hspec.shouldBe` [('a', True)]++ Hspec.it "handles duplicate insertions" $ do+ Extra.insertAll [('a', False), ('a', True)] [] `Hspec.shouldBe` [('a', True)]++ Hspec.it "inserts into a non-empty list" $ do+ Extra.insertAll [('a', False)] [('b', True)] `Hspec.shouldBe` [('b', True), ('a', False)]++ Hspec.it "does not modify the original list" $ do+ Extra.insertAll [] [('a', False), ('a', True)] `Hspec.shouldBe` [('a', False), ('a', True)]++ Hspec.describe "insert" $ do+ Hspec.it "inserts into an empty list" $ do+ Extra.insert ('a', False) [] `Hspec.shouldBe` [('a', False)]++ Hspec.it "prefers the original element" $ do+ Extra.insert ('a', False) [('a', True)] `Hspec.shouldBe` [('a', True)]++ Hspec.it "inserts into a non-empty list" $ do+ Extra.insert ('a', False) [('b', True)] `Hspec.shouldBe` [('b', True), ('a', False)]++ Hspec.describe "insertBy" $ do+ Hspec.it "inserts into an empty list" $ do+ Extra.insertBy (==) 'a' "" `Hspec.shouldBe` "a"++ Hspec.it "does not insert a duplicate" $ do+ Extra.insertBy (==) 'a' "a" `Hspec.shouldBe` "a"++ Hspec.it "does not insert a duplicate earlier" $ do+ Extra.insertBy (==) 'a' "ab" `Hspec.shouldBe` "ab"++ Hspec.it "does not insert a duplicate later" $ do+ Extra.insertBy (==) 'a' "ba" `Hspec.shouldBe` "ba"++ Hspec.it "prefers the original element" $ do+ Extra.insertBy (Function.on (==) Char.toLower) 'a' "A" `Hspec.shouldBe` "A"++ Hspec.it "inserts into a non-empty list" $ do+ Extra.insertBy (==) 'a' "b" `Hspec.shouldBe` "ba"
+ source/test-suite/Patrol/Type/AppContextSpec.hs view
@@ -0,0 +1,58 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.AppContextSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Text as Text+import qualified Data.Time as Time+import qualified Patrol.Type.AppContext as AppContext+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.AppContext" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let appContext = AppContext.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON appContext `Hspec.shouldBe` json++ Hspec.it "works with an app build" $ do+ let appContext = AppContext.empty {AppContext.appBuild = Text.pack "example-app-build"}+ json = [Aeson.aesonQQ| { "app_build": "example-app-build" } |]+ Aeson.toJSON appContext `Hspec.shouldBe` json++ Hspec.it "works with an app identifier" $ do+ let appContext = AppContext.empty {AppContext.appIdentifier = Text.pack "example-app-identifier"}+ json = [Aeson.aesonQQ| { "app_identifier": "example-app-identifier" } |]+ Aeson.toJSON appContext `Hspec.shouldBe` json++ Hspec.it "works with an app memory" $ do+ let appContext = AppContext.empty {AppContext.appMemory = Just 0}+ json = [Aeson.aesonQQ| { "app_memory": 0 } |]+ Aeson.toJSON appContext `Hspec.shouldBe` json++ Hspec.it "works with an app name" $ do+ let appContext = AppContext.empty {AppContext.appName = Text.pack "example-app-name"}+ json = [Aeson.aesonQQ| { "app_name": "example-app-name" } |]+ Aeson.toJSON appContext `Hspec.shouldBe` json++ Hspec.it "works with an app start time" $ do+ let appContext = AppContext.empty {AppContext.appStartTime = Just $ Time.UTCTime (Time.fromGregorian 1970 1 1) 0}+ json = [Aeson.aesonQQ| { "app_start_time": "1970-01-01T00:00:00Z" } |]+ Aeson.toJSON appContext `Hspec.shouldBe` json++ Hspec.it "works with an app version" $ do+ let appContext = AppContext.empty {AppContext.appVersion = Text.pack "example-app-version"}+ json = [Aeson.aesonQQ| { "app_version": "example-app-version" } |]+ Aeson.toJSON appContext `Hspec.shouldBe` json++ Hspec.it "works with a build type" $ do+ let appContext = AppContext.empty {AppContext.buildType = Text.pack "example-build-type"}+ json = [Aeson.aesonQQ| { "build_type": "example-build-type" } |]+ Aeson.toJSON appContext `Hspec.shouldBe` json++ Hspec.it "works with a device app hash" $ do+ let appContext = AppContext.empty {AppContext.deviceAppHash = Text.pack "example-device-app-hash"}+ json = [Aeson.aesonQQ| { "device_app_hash": "example-device-app-hash" } |]+ Aeson.toJSON appContext `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/AppleDebugImageSpec.hs view
@@ -0,0 +1,57 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.AppleDebugImageSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Text as Text+import qualified Patrol.Type.AppleDebugImage as AppleDebugImage+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.AppleDebugImage" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let appleDebugImage = AppleDebugImage.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON appleDebugImage `Hspec.shouldBe` json++ Hspec.it "works with an architecture" $ do+ let appleDebugImage = AppleDebugImage.empty {AppleDebugImage.arch = Text.pack "example-arch"}+ json = [Aeson.aesonQQ| { "arch": "example-arch" } |]+ Aeson.toJSON appleDebugImage `Hspec.shouldBe` json++ Hspec.it "works with a CPU subtype" $ do+ let appleDebugImage = AppleDebugImage.empty {AppleDebugImage.cpuSubtype = Just 0}+ json = [Aeson.aesonQQ| { "cpu_subtype": 0 } |]+ Aeson.toJSON appleDebugImage `Hspec.shouldBe` json++ Hspec.it "works with a CPU type" $ do+ let appleDebugImage = AppleDebugImage.empty {AppleDebugImage.cpuType = Just 0}+ json = [Aeson.aesonQQ| { "cpu_type": 0 } |]+ Aeson.toJSON appleDebugImage `Hspec.shouldBe` json++ Hspec.it "works with an image address" $ do+ let appleDebugImage = AppleDebugImage.empty {AppleDebugImage.imageAddr = Text.pack "example-image-addr"}+ json = [Aeson.aesonQQ| { "image_addr": "example-image-addr" } |]+ Aeson.toJSON appleDebugImage `Hspec.shouldBe` json++ Hspec.it "works with an image size" $ do+ let appleDebugImage = AppleDebugImage.empty {AppleDebugImage.imageSize = Just 0}+ json = [Aeson.aesonQQ| { "image_size": 0 } |]+ Aeson.toJSON appleDebugImage `Hspec.shouldBe` json++ Hspec.it "works with an image VM address" $ do+ let appleDebugImage = AppleDebugImage.empty {AppleDebugImage.imageVmaddr = Text.pack "example-image-vmaddr"}+ json = [Aeson.aesonQQ| { "image_vmaddr": "example-image-vmaddr" } |]+ Aeson.toJSON appleDebugImage `Hspec.shouldBe` json++ Hspec.it "works with a name" $ do+ let appleDebugImage = AppleDebugImage.empty {AppleDebugImage.name = Text.pack "example-name"}+ json = [Aeson.aesonQQ| { "name": "example-name" } |]+ Aeson.toJSON appleDebugImage `Hspec.shouldBe` json++ Hspec.it "works with a UUID" $ do+ let appleDebugImage = AppleDebugImage.empty {AppleDebugImage.uuid = Text.pack "example-uuid"}+ json = [Aeson.aesonQQ| { "uuid": "example-uuid" } |]+ Aeson.toJSON appleDebugImage `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/BreadcrumbSpec.hs view
@@ -0,0 +1,57 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.BreadcrumbSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Map as Map+import qualified Data.Text as Text+import qualified Data.Time as Time+import qualified Patrol.Type.Breadcrumb as Breadcrumb+import qualified Patrol.Type.BreadcrumbType as BreadcrumbType+import qualified Patrol.Type.EventId as EventId+import qualified Patrol.Type.Level as Level+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.Breadcrumb" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let breadcrumb = Breadcrumb.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON breadcrumb `Hspec.shouldBe` json++ Hspec.it "works with a category" $ do+ let breadcrumb = Breadcrumb.empty {Breadcrumb.category = Text.pack "example-category"}+ json = [Aeson.aesonQQ| { "category": "example-category" } |]+ Aeson.toJSON breadcrumb `Hspec.shouldBe` json++ Hspec.it "works with some data" $ do+ let breadcrumb = Breadcrumb.empty {Breadcrumb.data_ = Map.singleton (Text.pack "example-data") (Aeson.Bool True)}+ json = [Aeson.aesonQQ| { "data": { "example-data": true } } |]+ Aeson.toJSON breadcrumb `Hspec.shouldBe` json++ Hspec.it "works with an event ID" $ do+ let breadcrumb = Breadcrumb.empty {Breadcrumb.eventId = Just EventId.empty}+ json = [Aeson.aesonQQ| { "event_id": "00000000000000000000000000000000" } |]+ Aeson.toJSON breadcrumb `Hspec.shouldBe` json++ Hspec.it "works with a level" $ do+ let breadcrumb = Breadcrumb.empty {Breadcrumb.level = Just Level.Debug}+ json = [Aeson.aesonQQ| { "level": "debug" } |]+ Aeson.toJSON breadcrumb `Hspec.shouldBe` json++ Hspec.it "works with a message" $ do+ let breadcrumb = Breadcrumb.empty {Breadcrumb.message = Text.pack "example-message"}+ json = [Aeson.aesonQQ| { "message": "example-message" } |]+ Aeson.toJSON breadcrumb `Hspec.shouldBe` json++ Hspec.it "works with a timestamp" $ do+ let breadcrumb = Breadcrumb.empty {Breadcrumb.timestamp = Just $ Time.UTCTime (Time.fromGregorian 1970 1 1) 0}+ json = [Aeson.aesonQQ| { "timestamp": "1970-01-01T00:00:00Z" } |]+ Aeson.toJSON breadcrumb `Hspec.shouldBe` json++ Hspec.it "works with a type" $ do+ let breadcrumb = Breadcrumb.empty {Breadcrumb.type_ = Just BreadcrumbType.Default}+ json = [Aeson.aesonQQ| { "type": "default" } |]+ Aeson.toJSON breadcrumb `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/BreadcrumbTypeSpec.hs view
@@ -0,0 +1,20 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.BreadcrumbTypeSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Patrol.Type.BreadcrumbType as BreadcrumbType+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.BreadcrumbType" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works for Default" $ do+ Aeson.toJSON BreadcrumbType.Default `Hspec.shouldBe` [Aeson.aesonQQ| "default" |]++ Hspec.it "works for Http" $ do+ Aeson.toJSON BreadcrumbType.Http `Hspec.shouldBe` [Aeson.aesonQQ| "http" |]++ Hspec.it "works for Navigation" $ do+ Aeson.toJSON BreadcrumbType.Navigation `Hspec.shouldBe` [Aeson.aesonQQ| "navigation" |]
+ source/test-suite/Patrol/Type/BreadcrumbsSpec.hs view
@@ -0,0 +1,24 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.BreadcrumbsSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Text as Text+import qualified Patrol.Type.Breadcrumb as Breadcrumb+import qualified Patrol.Type.Breadcrumbs as Breadcrumbs+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.Breadcrumbs" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let breadcrumbs = Breadcrumbs.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON breadcrumbs `Hspec.shouldBe` json++ Hspec.it "works with a value" $ do+ let breadcrumb = Breadcrumb.empty {Breadcrumb.category = Text.pack "example-category"}+ breadcrumbs = Breadcrumbs.empty {Breadcrumbs.values = [breadcrumb]}+ json = [Aeson.aesonQQ| { "values": [ { "category": "example-category" } ] } |]+ Aeson.toJSON breadcrumbs `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/BrowserContextSpec.hs view
@@ -0,0 +1,27 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.BrowserContextSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Text as Text+import qualified Patrol.Type.BrowserContext as BrowserContext+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.BrowserContext" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let browserContext = BrowserContext.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON browserContext `Hspec.shouldBe` json++ Hspec.it "works with a name" $ do+ let browserContext = BrowserContext.empty {BrowserContext.name = Text.pack "example-name"}+ json = [Aeson.aesonQQ| { "name": "example-name" } |]+ Aeson.toJSON browserContext `Hspec.shouldBe` json++ Hspec.it "works with a version" $ do+ let browserContext = BrowserContext.empty {BrowserContext.version = Text.pack "example-version"}+ json = [Aeson.aesonQQ| { "version": "example-version" } |]+ Aeson.toJSON browserContext `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/CErrorSpec.hs view
@@ -0,0 +1,27 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.CErrorSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Text as Text+import qualified Patrol.Type.CError as CError+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.CError" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let cError = CError.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON cError `Hspec.shouldBe` json++ Hspec.it "works with a name" $ do+ let cError = CError.empty {CError.name = Text.pack "example-name"}+ json = [Aeson.aesonQQ| { "name": "example-name" } |]+ Aeson.toJSON cError `Hspec.shouldBe` json++ Hspec.it "works with a number" $ do+ let cError = CError.empty {CError.number = Just 0}+ json = [Aeson.aesonQQ| { "number": 0 } |]+ Aeson.toJSON cError `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/ClientSdkInfoSpec.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.ClientSdkInfoSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Text as Text+import qualified Patrol.Type.ClientSdkInfo as ClientSdkInfo+import qualified Patrol.Type.ClientSdkPackage as ClientSdkPackage+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.ClientSdkInfo" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let clientSdkInfo = ClientSdkInfo.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON clientSdkInfo `Hspec.shouldBe` json++ Hspec.it "works with an integration" $ do+ let clientSdkInfo = ClientSdkInfo.empty {ClientSdkInfo.integrations = [Text.pack "example-integration"]}+ json = [Aeson.aesonQQ| { "integrations": [ "example-integration" ] } |]+ Aeson.toJSON clientSdkInfo `Hspec.shouldBe` json++ Hspec.it "works with a name" $ do+ let clientSdkInfo = ClientSdkInfo.empty {ClientSdkInfo.name = Text.pack "example-name"}+ json = [Aeson.aesonQQ| { "name": "example-name" } |]+ Aeson.toJSON clientSdkInfo `Hspec.shouldBe` json++ Hspec.it "works with a package" $ do+ let clientSdkPackage = ClientSdkPackage.empty {ClientSdkPackage.name = Text.pack "example-name"}+ clientSdkInfo = ClientSdkInfo.empty {ClientSdkInfo.packages = [clientSdkPackage]}+ json = [Aeson.aesonQQ| { "packages": [ { "name": "example-name" } ] } |]+ Aeson.toJSON clientSdkInfo `Hspec.shouldBe` json++ Hspec.it "works with a version" $ do+ let clientSdkInfo = ClientSdkInfo.empty {ClientSdkInfo.version = Text.pack "example-version"}+ json = [Aeson.aesonQQ| { "version": "example-version" } |]+ Aeson.toJSON clientSdkInfo `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/ClientSdkPackageSpec.hs view
@@ -0,0 +1,27 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.ClientSdkPackageSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Text as Text+import qualified Patrol.Type.ClientSdkPackage as ClientSdkPackage+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.ClientSdkPackage" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let clientSdkPackage = ClientSdkPackage.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON clientSdkPackage `Hspec.shouldBe` json++ Hspec.it "works with a name" $ do+ let clientSdkPackage = ClientSdkPackage.empty {ClientSdkPackage.name = Text.pack "example-name"}+ json = [Aeson.aesonQQ| { "name": "example-name" } |]+ Aeson.toJSON clientSdkPackage `Hspec.shouldBe` json++ Hspec.it "works with a version" $ do+ let clientSdkPackage = ClientSdkPackage.empty {ClientSdkPackage.version = Text.pack "example-version"}+ json = [Aeson.aesonQQ| { "version": "example-version" } |]+ Aeson.toJSON clientSdkPackage `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/ContextSpec.hs view
@@ -0,0 +1,60 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.ContextSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Map as Map+import qualified Data.Text as Text+import qualified Patrol.Type.AppContext as AppContext+import qualified Patrol.Type.BrowserContext as BrowserContext+import qualified Patrol.Type.Context as Context+import qualified Patrol.Type.DeviceContext as DeviceContext+import qualified Patrol.Type.GpuContext as GpuContext+import qualified Patrol.Type.OsContext as OsContext+import qualified Patrol.Type.RuntimeContext as RuntimeContext+import qualified Patrol.Type.TraceContext as TraceContext+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.Context" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works with app" $ do+ let context = Context.App AppContext.empty {AppContext.appBuild = Text.pack "example-app-build"}+ json = [Aeson.aesonQQ| { "app_build": "example-app-build" } |]+ Aeson.toJSON context `Hspec.shouldBe` json++ Hspec.it "works with browser" $ do+ let context = Context.Browser BrowserContext.empty {BrowserContext.name = Text.pack "example-name"}+ json = [Aeson.aesonQQ| { "name": "example-name" } |]+ Aeson.toJSON context `Hspec.shouldBe` json++ Hspec.it "works with device" $ do+ let context = Context.Device DeviceContext.empty {DeviceContext.name = Text.pack "example-name"}+ json = [Aeson.aesonQQ| { "name": "example-name" } |]+ Aeson.toJSON context `Hspec.shouldBe` json++ Hspec.it "works with gpu" $ do+ let context = Context.Gpu GpuContext.empty {GpuContext.name = Text.pack "example-name"}+ json = [Aeson.aesonQQ| { "name": "example-name" } |]+ Aeson.toJSON context `Hspec.shouldBe` json++ Hspec.it "works with os" $ do+ let context = Context.Os OsContext.empty {OsContext.name = Text.pack "example-name"}+ json = [Aeson.aesonQQ| { "name": "example-name" } |]+ Aeson.toJSON context `Hspec.shouldBe` json++ Hspec.it "works with runtime" $ do+ let context = Context.Runtime RuntimeContext.empty {RuntimeContext.name = Text.pack "example-name"}+ json = [Aeson.aesonQQ| { "name": "example-name" } |]+ Aeson.toJSON context `Hspec.shouldBe` json++ Hspec.it "works with trace" $ do+ let context = Context.Trace TraceContext.empty {TraceContext.op = Text.pack "example-op"}+ json = [Aeson.aesonQQ| { "op": "example-op" } |]+ Aeson.toJSON context `Hspec.shouldBe` json++ Hspec.it "works with other" $ do+ let context = Context.Other . Map.singleton (Text.pack "example-key") $ Aeson.Bool True+ json = [Aeson.aesonQQ| { "example-key": true } |]+ Aeson.toJSON context `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/DebugImageSpec.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.DebugImageSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Map as Map+import qualified Data.Text as Text+import qualified Patrol.Type.AppleDebugImage as AppleDebugImage+import qualified Patrol.Type.DebugImage as DebugImage+import qualified Patrol.Type.NativeDebugImage as NativeDebugImage+import qualified Patrol.Type.ProguardDebugImage as ProguardDebugImage+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.DebugImage" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works with apple" $ do+ let appleDebugImage = AppleDebugImage.empty {AppleDebugImage.arch = Text.pack "example-arch"}+ debugImage = DebugImage.Apple appleDebugImage+ json = [Aeson.aesonQQ| { "arch": "example-arch" } |]+ Aeson.toJSON debugImage `Hspec.shouldBe` json++ Hspec.it "works with native" $ do+ let nativeDebugImage = NativeDebugImage.empty {NativeDebugImage.arch = Text.pack "example-arch"}+ debugImage = DebugImage.Native nativeDebugImage+ json = [Aeson.aesonQQ| { "arch": "example-arch" } |]+ Aeson.toJSON debugImage `Hspec.shouldBe` json++ Hspec.it "works with proguard" $ do+ let proguardDebugImage = ProguardDebugImage.empty {ProguardDebugImage.uuid = Text.pack "example-uuid"}+ debugImage = DebugImage.Proguard proguardDebugImage+ json = [Aeson.aesonQQ| { "uuid": "example-uuid" } |]+ Aeson.toJSON debugImage `Hspec.shouldBe` json++ Hspec.it "works with other" $ do+ let debugImage = DebugImage.Other . Map.singleton (Text.pack "example-key") $ Aeson.Bool True+ json = [Aeson.aesonQQ| { "example-key": true } |]+ Aeson.toJSON debugImage `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/DebugMetaSpec.hs view
@@ -0,0 +1,32 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.DebugMetaSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Map as Map+import qualified Data.Text as Text+import qualified Patrol.Type.DebugImage as DebugImage+import qualified Patrol.Type.DebugMeta as DebugMeta+import qualified Patrol.Type.SystemSdkInfo as SystemSdkInfo+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.DebugMeta" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let debugMeta = DebugMeta.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON debugMeta `Hspec.shouldBe` json++ Hspec.it "works with an image" $ do+ let image = DebugImage.Other . Map.singleton (Text.pack "example-image") $ Aeson.Bool True+ debugMeta = DebugMeta.empty {DebugMeta.images = [image]}+ json = [Aeson.aesonQQ| { "images": [ { "example-image": true } ] } |]+ Aeson.toJSON debugMeta `Hspec.shouldBe` json++ Hspec.it "works with some SDK info" $ do+ let systemSdkInfo = SystemSdkInfo.empty {SystemSdkInfo.versionMajor = Just 0}+ debugMeta = DebugMeta.empty {DebugMeta.sdkInfo = Just systemSdkInfo}+ json = [Aeson.aesonQQ| { "sdk_info": { "version_major": 0 } } |]+ Aeson.toJSON debugMeta `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/DeviceContextSpec.hs view
@@ -0,0 +1,198 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.DeviceContextSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Text as Text+import qualified Data.Time as Time+import qualified Patrol.Type.DeviceContext as DeviceContext+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.DeviceContext" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let deviceContext = DeviceContext.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with arch" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.arch = Text.pack "example-arch"}+ json = [Aeson.aesonQQ| { "arch": "example-arch" } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with batteryLevel" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.batteryLevel = Just 0.1}+ json = [Aeson.aesonQQ| { "battery_level": 0.1 } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with batteryStatus" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.batteryStatus = Text.pack "example-batteryStatus"}+ json = [Aeson.aesonQQ| { "battery_status": "example-batteryStatus" } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with bootTime" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.bootTime = Just $ Time.UTCTime (Time.fromGregorian 1970 1 1) 0}+ json = [Aeson.aesonQQ| { "boot_time": "1970-01-01T00:00:00Z" } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with brand" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.brand = Text.pack "example-brand"}+ json = [Aeson.aesonQQ| { "brand": "example-brand" } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with charging" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.charging = Just True}+ json = [Aeson.aesonQQ| { "charging": true } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with cpuDescription" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.cpuDescription = Text.pack "example-cpuDescription"}+ json = [Aeson.aesonQQ| { "cpu_description": "example-cpuDescription" } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with deviceType" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.deviceType = Text.pack "example-deviceType"}+ json = [Aeson.aesonQQ| { "device_type": "example-deviceType" } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with deviceUniqueIdentifier" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.deviceUniqueIdentifier = Text.pack "example-deviceUniqueIdentifier"}+ json = [Aeson.aesonQQ| { "device_unique_identifier": "example-deviceUniqueIdentifier" } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with externalFreeStorage" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.externalFreeStorage = Just 0}+ json = [Aeson.aesonQQ| { "external_free_storage": 0 } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with externalStorageSize" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.externalStorageSize = Just 0}+ json = [Aeson.aesonQQ| { "external_storage_size": 0 } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with family" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.family = Text.pack "example-family"}+ json = [Aeson.aesonQQ| { "family": "example-family" } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with freeMemory" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.freeMemory = Just 0}+ json = [Aeson.aesonQQ| { "free_memory": 0 } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with freeStorage" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.freeStorage = Just 0}+ json = [Aeson.aesonQQ| { "free_storage": 0 } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with lowMemory" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.lowMemory = Just True}+ json = [Aeson.aesonQQ| { "low_memory": true } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with manufacturer" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.manufacturer = Text.pack "example-manufacturer"}+ json = [Aeson.aesonQQ| { "manufacturer": "example-manufacturer" } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with memorySize" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.memorySize = Just 0}+ json = [Aeson.aesonQQ| { "memory_size": 0 } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with model" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.model = Text.pack "example-model"}+ json = [Aeson.aesonQQ| { "model": "example-model" } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with modelId" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.modelId = Text.pack "example-modelId"}+ json = [Aeson.aesonQQ| { "model_id": "example-modelId" } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with name" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.name = Text.pack "example-name"}+ json = [Aeson.aesonQQ| { "name": "example-name" } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with online" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.online = Just True}+ json = [Aeson.aesonQQ| { "online": true } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with orientation" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.orientation = Text.pack "example-orientation"}+ json = [Aeson.aesonQQ| { "orientation": "example-orientation" } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with processorCount" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.processorCount = Just 0}+ json = [Aeson.aesonQQ| { "processor_count": 0 } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with processorFrequency" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.processorFrequency = Just 0.1}+ json = [Aeson.aesonQQ| { "processor_frequency": 0.1 } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with screenDensity" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.screenDensity = Just 0.1}+ json = [Aeson.aesonQQ| { "screen_density": 0.1 } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with screenDpi" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.screenDpi = Just 0.1}+ json = [Aeson.aesonQQ| { "screen_dpi": 0.1 } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with screenResolution" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.screenResolution = Text.pack "example-screenResolution"}+ json = [Aeson.aesonQQ| { "screen_resolution": "example-screenResolution" } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with simulator" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.simulator = Just True}+ json = [Aeson.aesonQQ| { "simulator": true } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with storageSize" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.storageSize = Just 0}+ json = [Aeson.aesonQQ| { "storage_size": 0 } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with supportsAccelerometer" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.supportsAccelerometer = Just True}+ json = [Aeson.aesonQQ| { "supports_accelerometer": true } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with supportsAudio" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.supportsAudio = Just True}+ json = [Aeson.aesonQQ| { "supports_audio": true } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with supportsGyroscope" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.supportsGyroscope = Just True}+ json = [Aeson.aesonQQ| { "supports_gyroscope": true } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with supportsLocationService" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.supportsLocationService = Just True}+ json = [Aeson.aesonQQ| { "supports_location_service": true } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with supportsVibration" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.supportsVibration = Just True}+ json = [Aeson.aesonQQ| { "supports_vibration": true } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with timezone" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.timezone = Text.pack "example-timezone"}+ json = [Aeson.aesonQQ| { "timezone": "example-timezone" } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json++ Hspec.it "works with usableMemory" $ do+ let deviceContext = DeviceContext.empty {DeviceContext.usableMemory = Just 0}+ json = [Aeson.aesonQQ| { "usable_memory": 0 } |]+ Aeson.toJSON deviceContext `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/DsnSpec.hs view
@@ -0,0 +1,86 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.DsnSpec where++import qualified Data.Text as Text+import qualified Data.Text.Encoding as Text+import qualified Network.URI.Static as Uri+import qualified Patrol.Type.Dsn as Dsn+import qualified Patrol.Version as Version+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.Dsn" $ do+ Hspec.describe "fromUri" $ do+ Hspec.it "fails with an invalid DSN" $ do+ Dsn.fromUri [Uri.uri|a:|] `Hspec.shouldBe` Nothing++ Hspec.it "succeeds with a minimal DSN" $ do+ let dsn =+ Dsn.Dsn+ { Dsn.protocol = Text.singleton 'a',+ Dsn.publicKey = Text.singleton 'b',+ Dsn.secretKey = Text.empty,+ Dsn.host = Text.singleton 'c',+ Dsn.port = Nothing,+ Dsn.path = Text.singleton '/',+ Dsn.projectId = Text.singleton 'd'+ }+ Dsn.fromUri [Uri.uri|a://b@c/d|] `Hspec.shouldBe` Just dsn++ Hspec.it "succeeds with a maximal DSN" $ do+ let dsn =+ Dsn.Dsn+ { Dsn.protocol = Text.singleton 'a',+ Dsn.publicKey = Text.singleton 'b',+ Dsn.secretKey = Text.singleton 'c',+ Dsn.host = Text.singleton 'd',+ Dsn.port = Just 5,+ Dsn.path = Text.pack "/f/",+ Dsn.projectId = Text.singleton 'g'+ }+ Dsn.fromUri [Uri.uri|a://b:c@d:5/f/g|] `Hspec.shouldBe` Just dsn++ Hspec.it "fails with a query" $ do+ Dsn.fromUri [Uri.uri|a://b@c/d?|] `Hspec.shouldBe` Nothing++ Hspec.it "fails with a fragment" $ do+ Dsn.fromUri [Uri.uri|a://b@c/d#|] `Hspec.shouldBe` Nothing++ Hspec.describe "intoUri" $ do+ Hspec.it "converts a minimal DSN into URI" $ do+ let dsn =+ Dsn.Dsn+ { Dsn.protocol = Text.singleton 'a',+ Dsn.publicKey = Text.singleton 'b',+ Dsn.secretKey = Text.empty,+ Dsn.host = Text.singleton 'c',+ Dsn.port = Nothing,+ Dsn.path = Text.singleton '/',+ Dsn.projectId = Text.singleton 'd'+ }+ Dsn.intoUri dsn `Hspec.shouldBe` [Uri.uri|a://b@c/d|]++ Hspec.it "converts a maximal DSN into URI" $ do+ let dsn =+ Dsn.Dsn+ { Dsn.protocol = Text.singleton 'a',+ Dsn.publicKey = Text.singleton 'b',+ Dsn.secretKey = Text.singleton 'c',+ Dsn.host = Text.singleton 'd',+ Dsn.port = Just 5,+ Dsn.path = Text.pack "/f/",+ Dsn.projectId = Text.singleton 'g'+ }+ Dsn.intoUri dsn `Hspec.shouldBe` [Uri.uri|a://b:c@d:5/f/g|]++ Hspec.describe "intoAuthorization" $ do+ Hspec.it "works without a secret key" $ do+ dsn <- maybe (fail "invalid DSN") pure $ Dsn.fromUri [Uri.uri|a://b@c/d|]+ let byteString = Text.encodeUtf8 . Text.pack $ "Sentry sentry_version=7,sentry_client=patrol/" <> Version.string <> ",sentry_key=b"+ Dsn.intoAuthorization dsn `Hspec.shouldBe` byteString++ Hspec.it "works with a secret key" $ do+ dsn <- maybe (fail "invalid DSN") pure $ Dsn.fromUri [Uri.uri|a://b:c@d/e|]+ let byteString = Text.encodeUtf8 . Text.pack $ "Sentry sentry_version=7,sentry_client=patrol/" <> Version.string <> ",sentry_key=b,sentry_secret=c"+ Dsn.intoAuthorization dsn `Hspec.shouldBe` byteString
+ source/test-suite/Patrol/Type/ErrorTypeSpec.hs view
@@ -0,0 +1,131 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.ErrorTypeSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Patrol.Type.ErrorType as ErrorType+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.ErrorType" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works for ClockDrift" $ do+ Aeson.toJSON ErrorType.ClockDrift `Hspec.shouldBe` [Aeson.aesonQQ| "clock_drift" |]++ Hspec.it "works for FetchGenericError" $ do+ Aeson.toJSON ErrorType.FetchGenericError `Hspec.shouldBe` [Aeson.aesonQQ| "fetch_generic_error" |]++ Hspec.it "works for FetchInvalidEncoding" $ do+ Aeson.toJSON ErrorType.FetchInvalidEncoding `Hspec.shouldBe` [Aeson.aesonQQ| "fetch_invalid_source_encoding" |]++ Hspec.it "works for FetchInvalidHttpCode" $ do+ Aeson.toJSON ErrorType.FetchInvalidHttpCode `Hspec.shouldBe` [Aeson.aesonQQ| "fetch_invalid_http_code" |]++ Hspec.it "works for FetchTimeout" $ do+ Aeson.toJSON ErrorType.FetchTimeout `Hspec.shouldBe` [Aeson.aesonQQ| "fetch_timeout" |]++ Hspec.it "works for FetchTooLarge" $ do+ Aeson.toJSON ErrorType.FetchTooLarge `Hspec.shouldBe` [Aeson.aesonQQ| "fetch_too_large" |]++ Hspec.it "works for FutureTimestamp" $ do+ Aeson.toJSON ErrorType.FutureTimestamp `Hspec.shouldBe` [Aeson.aesonQQ| "future_timestamp" |]++ Hspec.it "works for InvalidAttribute" $ do+ Aeson.toJSON ErrorType.InvalidAttribute `Hspec.shouldBe` [Aeson.aesonQQ| "invalid_attribute" |]++ Hspec.it "works for InvalidData" $ do+ Aeson.toJSON ErrorType.InvalidData `Hspec.shouldBe` [Aeson.aesonQQ| "invalid_data" |]++ Hspec.it "works for InvalidEnvironment" $ do+ Aeson.toJSON ErrorType.InvalidEnvironment `Hspec.shouldBe` [Aeson.aesonQQ| "invalid_environment" |]++ Hspec.it "works for JsFetchTimeout" $ do+ Aeson.toJSON ErrorType.JsFetchTimeout `Hspec.shouldBe` [Aeson.aesonQQ| "js_fetch_timeout" |]++ Hspec.it "works for JsGenericFetchError" $ do+ Aeson.toJSON ErrorType.JsGenericFetchError `Hspec.shouldBe` [Aeson.aesonQQ| "js_generic_fetch_error" |]++ Hspec.it "works for JsInvalidContent" $ do+ Aeson.toJSON ErrorType.JsInvalidContent `Hspec.shouldBe` [Aeson.aesonQQ| "js_invalid_content" |]++ Hspec.it "works for JsInvalidHttpCode" $ do+ Aeson.toJSON ErrorType.JsInvalidHttpCode `Hspec.shouldBe` [Aeson.aesonQQ| "js_invalid_http_code" |]++ Hspec.it "works for JsInvalidSourceEncoding" $ do+ Aeson.toJSON ErrorType.JsInvalidSourceEncoding `Hspec.shouldBe` [Aeson.aesonQQ| "js_invalid_source_encoding" |]++ Hspec.it "works for JsInvalidSourcemap" $ do+ Aeson.toJSON ErrorType.JsInvalidSourcemap `Hspec.shouldBe` [Aeson.aesonQQ| "js_invalid_source" |]++ Hspec.it "works for JsInvalidSourcemapLocation" $ do+ Aeson.toJSON ErrorType.JsInvalidSourcemapLocation `Hspec.shouldBe` [Aeson.aesonQQ| "js_invalid_sourcemap_location" |]++ Hspec.it "works for JsMissingSource" $ do+ Aeson.toJSON ErrorType.JsMissingSource `Hspec.shouldBe` [Aeson.aesonQQ| "js_no_source" |]++ Hspec.it "works for JsNoColumn" $ do+ Aeson.toJSON ErrorType.JsNoColumn `Hspec.shouldBe` [Aeson.aesonQQ| "js_no_column" |]++ Hspec.it "works for JsTooLarge" $ do+ Aeson.toJSON ErrorType.JsTooLarge `Hspec.shouldBe` [Aeson.aesonQQ| "js_too_large" |]++ Hspec.it "works for JsTooManyRemoteSources" $ do+ Aeson.toJSON ErrorType.JsTooManyRemoteSources `Hspec.shouldBe` [Aeson.aesonQQ| "js_too_many_sources" |]++ Hspec.it "works for MissingAttribute" $ do+ Aeson.toJSON ErrorType.MissingAttribute `Hspec.shouldBe` [Aeson.aesonQQ| "missing_attribute" |]++ Hspec.it "works for NativeBadDsym" $ do+ Aeson.toJSON ErrorType.NativeBadDsym `Hspec.shouldBe` [Aeson.aesonQQ| "native_bad_dsym" |]++ Hspec.it "works for NativeInternalFailure" $ do+ Aeson.toJSON ErrorType.NativeInternalFailure `Hspec.shouldBe` [Aeson.aesonQQ| "native_internal_failure" |]++ Hspec.it "works for NativeMissingDsym" $ do+ Aeson.toJSON ErrorType.NativeMissingDsym `Hspec.shouldBe` [Aeson.aesonQQ| "native_missing_dsym" |]++ Hspec.it "works for NativeMissingOptionallyBundledDsym" $ do+ Aeson.toJSON ErrorType.NativeMissingOptionallyBundledDsym `Hspec.shouldBe` [Aeson.aesonQQ| "native_optionally_bundled_dsym" |]++ Hspec.it "works for NativeMissingSymbol" $ do+ Aeson.toJSON ErrorType.NativeMissingSymbol `Hspec.shouldBe` [Aeson.aesonQQ| "native_missing_symbol" |]++ Hspec.it "works for NativeMissingSystemDsym" $ do+ Aeson.toJSON ErrorType.NativeMissingSystemDsym `Hspec.shouldBe` [Aeson.aesonQQ| "native_missing_system_dsym" |]++ Hspec.it "works for NativeNoCrashedThread" $ do+ Aeson.toJSON ErrorType.NativeNoCrashedThread `Hspec.shouldBe` [Aeson.aesonQQ| "native_no_crashed_thread" |]++ Hspec.it "works for NativeSimulatorFrame" $ do+ Aeson.toJSON ErrorType.NativeSimulatorFrame `Hspec.shouldBe` [Aeson.aesonQQ| "native_simulator_frame" |]++ Hspec.it "works for NativeSymbolicatorFailed" $ do+ Aeson.toJSON ErrorType.NativeSymbolicatorFailed `Hspec.shouldBe` [Aeson.aesonQQ| "native_symbolicator_failed" |]++ Hspec.it "works for NativeUnknownImage" $ do+ Aeson.toJSON ErrorType.NativeUnknownImage `Hspec.shouldBe` [Aeson.aesonQQ| "native_unknown_image" |]++ Hspec.it "works for PastTimestamp" $ do+ Aeson.toJSON ErrorType.PastTimestamp `Hspec.shouldBe` [Aeson.aesonQQ| "past_timestamp" |]++ Hspec.it "works for ProguardMissingLineno" $ do+ Aeson.toJSON ErrorType.ProguardMissingLineno `Hspec.shouldBe` [Aeson.aesonQQ| "proguard_missing_lineno" |]++ Hspec.it "works for ProguardMissingMapping" $ do+ Aeson.toJSON ErrorType.ProguardMissingMapping `Hspec.shouldBe` [Aeson.aesonQQ| "proguard_missing_mapping" |]++ Hspec.it "works for RestrictedIp" $ do+ Aeson.toJSON ErrorType.RestrictedIp `Hspec.shouldBe` [Aeson.aesonQQ| "restricted_ip" |]++ Hspec.it "works for SecurityViolation" $ do+ Aeson.toJSON ErrorType.SecurityViolation `Hspec.shouldBe` [Aeson.aesonQQ| "security_violation" |]++ Hspec.it "works for TooLargeForCache" $ do+ Aeson.toJSON ErrorType.TooLargeForCache `Hspec.shouldBe` [Aeson.aesonQQ| "too_large_for_cache" |]++ Hspec.it "works for UnknownError" $ do+ Aeson.toJSON ErrorType.UnknownError `Hspec.shouldBe` [Aeson.aesonQQ| "unknown_error" |]++ Hspec.it "works for ValueTooLong" $ do+ Aeson.toJSON ErrorType.ValueTooLong `Hspec.shouldBe` [Aeson.aesonQQ| "value_too_long" |]
+ source/test-suite/Patrol/Type/EventIdSpec.hs view
@@ -0,0 +1,74 @@+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE TypeApplications #-}++module Patrol.Type.EventIdSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Text as Text+import qualified Data.UUID as Uuid+import qualified Data.UUID.V4 as Uuid+import qualified Patrol.Type.EventId as EventId+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.EventId" $ do+ Hspec.describe "fromUuid" $ do+ Hspec.it "converts from UUID" $ do+ uuid <- Uuid.nextRandom+ EventId.fromUuid uuid `Hspec.shouldBe` EventId.EventId uuid++ Hspec.describe "intoUuid" $ do+ Hspec.it "converts into UUID" $ do+ uuid <- Uuid.nextRandom+ EventId.intoUuid (EventId.fromUuid uuid) `Hspec.shouldBe` uuid++ Hspec.describe "random" $ do+ Hspec.it "generates a non-nil UUID" $ do+ eventId <- EventId.random+ eventId `Hspec.shouldNotBe` EventId.empty++ Hspec.describe "intoText" $ do+ Hspec.it "converts into text" $ do+ let eventId = EventId.fromUuid $ Uuid.fromWords64 0x0011223344556677 0x8899aabbccddeeff+ EventId.intoText eventId `Hspec.shouldBe` Text.pack "00112233445566778899aabbccddeeff"++ Hspec.describe "fromText" $ do+ Hspec.it "converts from text" $ do+ let eventId = EventId.fromUuid $ Uuid.fromWords64 0x0011223344556677 0x8899aabbccddeeff+ EventId.fromText (Text.pack "00112233445566778899aabbccddeeff") `Hspec.shouldBe` Just eventId++ Hspec.it "succeeds with uppercase digits" $ do+ let eventId = EventId.fromUuid $ Uuid.fromWords64 0x0011223344556677 0x8899aabbccddeeff+ EventId.fromText (Text.pack "00112233445566778899AABBCCDDEEFF") `Hspec.shouldBe` Just eventId++ Hspec.it "fails with not enough digits" $ do+ EventId.fromText (Text.pack "0123456789abcdef0123456789abcde") `Hspec.shouldBe` Nothing++ Hspec.it "fails with too many digits" $ do+ EventId.fromText (Text.pack "0123456789abcdef0123456789abcdef0") `Hspec.shouldBe` Nothing++ Hspec.it "fails with invalid hexadecimal" $ do+ EventId.fromText (Text.pack "Z123456789abcdef0123456789abcdef") `Hspec.shouldBe` Nothing+ EventId.fromText (Text.pack "0123456789Zbcdef0123456789abcdef") `Hspec.shouldBe` Nothing+ EventId.fromText (Text.pack "0123456789abcdef0123456789Zbcdef") `Hspec.shouldBe` Nothing++ Hspec.describe "FromJSON" $ do+ Hspec.it "works" $ do+ let json = [Aeson.aesonQQ| "00112233445566778899aabbccddeeff" |]+ eventId = EventId.fromUuid $ Uuid.fromWords64 0x0011223344556677 0x8899aabbccddeeff+ Aeson.fromJSON json `Hspec.shouldBe` Aeson.Success eventId++ Hspec.it "fails with not enough digits" $ do+ let json = [Aeson.aesonQQ| "" |]+ Aeson.fromJSON @EventId.EventId json `Hspec.shouldBe` Aeson.Error "invalid EventId"++ Hspec.it "fails with the wrong type" $ do+ let json = [Aeson.aesonQQ| null |]+ Aeson.fromJSON @EventId.EventId json `Hspec.shouldBe` Aeson.Error "parsing EventId failed, expected String, but encountered Null"++ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let eventId = EventId.fromUuid $ Uuid.fromWords64 0x0011223344556677 0x8899aabbccddeeff+ json = [Aeson.aesonQQ| "00112233445566778899aabbccddeeff" |]+ Aeson.toJSON eventId `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/EventProcessingErrorSpec.hs view
@@ -0,0 +1,27 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.EventProcessingErrorSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Text as Text+import qualified Patrol.Type.EventProcessingError as EventProcessingError+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.EventProcessingError" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let eventProcessingError = EventProcessingError.empty+ json = [Aeson.aesonQQ| { "type": "unknown_error" } |]+ Aeson.toJSON eventProcessingError `Hspec.shouldBe` json++ Hspec.it "works with a name" $ do+ let eventProcessingError = EventProcessingError.empty {EventProcessingError.name = Text.pack "example-name"}+ json = [Aeson.aesonQQ| { "type": "unknown_error", "name": "example-name" } |]+ Aeson.toJSON eventProcessingError `Hspec.shouldBe` json++ Hspec.it "works with a value" $ do+ let eventProcessingError = EventProcessingError.empty {EventProcessingError.value = Aeson.Bool True}+ json = [Aeson.aesonQQ| { "type": "unknown_error", "value": true } |]+ Aeson.toJSON eventProcessingError `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/EventSpec.hs view
@@ -0,0 +1,274 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.EventSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.ByteString.Lazy as LazyByteString+import qualified Data.Map as Map+import qualified Data.Maybe as Maybe+import qualified Data.Text as Text+import qualified Data.Text.Encoding as Text+import qualified Data.Time as Time+import qualified Network.HTTP.Client as Client+import qualified Network.HTTP.Types as Http+import qualified Network.URI.Static as Uri+import qualified Patrol.Constant as Constant+import qualified Patrol.Type.Breadcrumb as Breadcrumb+import qualified Patrol.Type.Breadcrumbs as Breadcrumbs+import qualified Patrol.Type.ClientSdkInfo as ClientSdkInfo+import qualified Patrol.Type.Context as Context+import qualified Patrol.Type.DebugImage as DebugImage+import qualified Patrol.Type.DebugMeta as DebugMeta+import qualified Patrol.Type.Dsn as Dsn+import qualified Patrol.Type.Event as Event+import qualified Patrol.Type.EventId as EventId+import qualified Patrol.Type.EventProcessingError as EventProcessingError+import qualified Patrol.Type.EventType as EventType+import qualified Patrol.Type.Exception as Exception+import qualified Patrol.Type.Exceptions as Exceptions+import qualified Patrol.Type.Level as Level+import qualified Patrol.Type.LogEntry as LogEntry+import qualified Patrol.Type.Platform as Platform+import qualified Patrol.Type.Request as Request+import qualified Patrol.Type.TransactionInfo as TransactionInfo+import qualified Patrol.Type.User as User+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.Event" $ do+ Hspec.describe "new" $ do+ Hspec.it "generates an ID" $ do+ event <- Event.new+ Event.eventId event `Hspec.shouldNotBe` EventId.empty++ Hspec.it "sets the timestamp" $ do+ event <- Event.new+ Event.timestamp event `Hspec.shouldSatisfy` Maybe.isJust++ Hspec.it "sets the platform" $ do+ event <- Event.new+ Event.platform event `Hspec.shouldBe` Just Platform.Haskell++ Hspec.it "sets the level" $ do+ event <- Event.new+ Event.level event `Hspec.shouldBe` Just Level.Error++ Hspec.it "sets the environment" $ do+ event <- Event.new+ Event.environment event `Hspec.shouldBe` Text.pack "production"++ Hspec.it "sets the version" $ do+ event <- Event.new+ Event.version event `Hspec.shouldBe` Constant.sentryVersion++ Hspec.it "sets the type" $ do+ event <- Event.new+ Event.type_ event `Hspec.shouldBe` Just EventType.Default++ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let event = Event.empty+ json = [Aeson.aesonQQ| { "event_id": "00000000000000000000000000000000" } |]+ Aeson.toJSON event `Hspec.shouldBe` json++ Hspec.it "works with a breadcrumb" $ do+ let breadcrumb = Breadcrumb.empty {Breadcrumb.category = Text.pack "example-category"}+ breadcrumbs = Breadcrumbs.empty {Breadcrumbs.values = [breadcrumb]}+ event = Event.empty {Event.breadcrumbs = Just breadcrumbs}+ json = [Aeson.aesonQQ| { "event_id": "00000000000000000000000000000000", "breadcrumbs": { "values": [ { "category": "example-category" } ] } } |]+ Aeson.toJSON event `Hspec.shouldBe` json++ Hspec.it "works with a context" $ do+ let context = Context.Other . Map.singleton (Text.pack "example-key") $ Aeson.Bool True+ contexts = Map.singleton (Text.pack "example-context") context+ event = Event.empty {Event.contexts = contexts}+ json = [Aeson.aesonQQ| { "event_id": "00000000000000000000000000000000", "contexts": { "example-context": { "example-key": true } } } |]+ Aeson.toJSON event `Hspec.shouldBe` json++ Hspec.it "works with some debug meta" $ do+ let image = DebugImage.Other . Map.singleton (Text.pack "example-image") $ Aeson.Bool True+ debugMeta = DebugMeta.empty {DebugMeta.images = [image]}+ event = Event.empty {Event.debugMeta = Just debugMeta}+ json = [Aeson.aesonQQ| { "event_id": "00000000000000000000000000000000", "debug_meta": { "images": [ { "example-image": true } ] } } |]+ Aeson.toJSON event `Hspec.shouldBe` json++ Hspec.it "works with a dist" $ do+ let event = Event.empty {Event.dist = Text.pack "example-dist"}+ json = [Aeson.aesonQQ| { "event_id": "00000000000000000000000000000000", "dist": "example-dist" } |]+ Aeson.toJSON event `Hspec.shouldBe` json++ Hspec.it "works with an environment" $ do+ let event = Event.empty {Event.environment = Text.pack "example-environment"}+ json = [Aeson.aesonQQ| { "event_id": "00000000000000000000000000000000", "environment": "example-environment" } |]+ Aeson.toJSON event `Hspec.shouldBe` json++ Hspec.it "works with an event processing error" $ do+ let eventProcessingError = EventProcessingError.empty+ event = Event.empty {Event.errors = [eventProcessingError]}+ json = [Aeson.aesonQQ| { "event_id": "00000000000000000000000000000000", "errors": [ { "type": "unknown_error" } ] } |]+ Aeson.toJSON event `Hspec.shouldBe` json++ Hspec.it "works with an exception" $ do+ let exception = Exception.empty {Exception.type_ = Text.pack "example-type"}+ exceptions = Exceptions.empty {Exceptions.values = [exception]}+ event = Event.empty {Event.exception = Just exceptions}+ json = [Aeson.aesonQQ| { "event_id": "00000000000000000000000000000000", "exception": { "values": [ { "type": "example-type" } ] } } |]+ Aeson.toJSON event `Hspec.shouldBe` json++ Hspec.it "works with some extra" $ do+ let event = Event.empty {Event.extra = Map.singleton (Text.pack "example-extra") (Aeson.Bool True)}+ json = [Aeson.aesonQQ| { "event_id": "00000000000000000000000000000000", "extra": { "example-extra": true } } |]+ Aeson.toJSON event `Hspec.shouldBe` json++ Hspec.it "works with a fingerprint" $ do+ let event = Event.empty {Event.fingerprint = [Text.pack "example-fingerprint"]}+ json = [Aeson.aesonQQ| { "event_id": "00000000000000000000000000000000", "fingerprint": ["example-fingerprint"] } |]+ Aeson.toJSON event `Hspec.shouldBe` json++ Hspec.it "works with a level" $ do+ let event = Event.empty {Event.level = Just Level.Error}+ json = [Aeson.aesonQQ| { "event_id": "00000000000000000000000000000000", "level": "error" } |]+ Aeson.toJSON event `Hspec.shouldBe` json++ Hspec.it "works with a log entry" $ do+ let logEntry = LogEntry.empty {LogEntry.message = Text.pack "example-message"}+ event = Event.empty {Event.logentry = Just logEntry}+ json = [Aeson.aesonQQ| { "event_id": "00000000000000000000000000000000", "logentry": { "message": "example-message" } } |]+ Aeson.toJSON event `Hspec.shouldBe` json++ Hspec.it "works with a logger" $ do+ let event = Event.empty {Event.logger = Text.pack "example-logger"}+ json = [Aeson.aesonQQ| { "event_id": "00000000000000000000000000000000", "logger": "example-logger" } |]+ Aeson.toJSON event `Hspec.shouldBe` json++ Hspec.it "works with some modules" $ do+ let event = Event.empty {Event.modules = Map.fromList [(Text.pack "module-name", Text.pack "module-version")]}+ json = [Aeson.aesonQQ| { "event_id": "00000000000000000000000000000000", "modules": { "module-name": "module-version" } } |]+ Aeson.toJSON event `Hspec.shouldBe` json++ Hspec.it "works with a platform" $ do+ let event = Event.empty {Event.platform = Just Platform.Haskell}+ json = [Aeson.aesonQQ| { "event_id": "00000000000000000000000000000000", "platform": "haskell" } |]+ Aeson.toJSON event `Hspec.shouldBe` json++ Hspec.it "works with a release" $ do+ let event = Event.empty {Event.release = Text.pack "example-release"}+ json = [Aeson.aesonQQ| { "event_id": "00000000000000000000000000000000", "release": "example-release" } |]+ Aeson.toJSON event `Hspec.shouldBe` json++ Hspec.it "works with a request" $ do+ let request = Request.empty {Request.fragment = Text.pack "example-fragment"}+ event = Event.empty {Event.request = Just request}+ json = [Aeson.aesonQQ| { "event_id": "00000000000000000000000000000000", "request": { "fragment": "example-fragment" } } |]+ Aeson.toJSON event `Hspec.shouldBe` json++ Hspec.it "works with an SDK" $ do+ let clientSdkInfo = ClientSdkInfo.empty {ClientSdkInfo.name = Text.pack "example-name"}+ event = Event.empty {Event.sdk = Just clientSdkInfo}+ json = [Aeson.aesonQQ| { "event_id": "00000000000000000000000000000000", "sdk": { "name": "example-name" } } |]+ Aeson.toJSON event `Hspec.shouldBe` json++ Hspec.it "works with a server name" $ do+ let event = Event.empty {Event.serverName = Text.pack "example-server-name"}+ json = [Aeson.aesonQQ| { "event_id": "00000000000000000000000000000000", "server_name": "example-server-name" } |]+ Aeson.toJSON event `Hspec.shouldBe` json++ Hspec.it "works with some tags" $ do+ let event = Event.empty {Event.tags = Map.fromList [(Text.pack "tag-key", Text.pack "tag-value")]}+ json = [Aeson.aesonQQ| { "event_id": "00000000000000000000000000000000", "tags": { "tag-key": "tag-value" } } |]+ Aeson.toJSON event `Hspec.shouldBe` json++ Hspec.it "works with a time spent" $ do+ let event = Event.empty {Event.timeSpent = Just 1.2}+ json = [Aeson.aesonQQ| { "event_id": "00000000000000000000000000000000", "time_spent": 1.2 } |]+ Aeson.toJSON event `Hspec.shouldBe` json++ Hspec.it "works with a timestamp" $ do+ let event = Event.empty {Event.timestamp = Just $ Time.UTCTime (Time.fromGregorian 1970 1 1) 0}+ json = [Aeson.aesonQQ| { "event_id": "00000000000000000000000000000000", "timestamp": "1970-01-01T00:00:00Z" } |]+ Aeson.toJSON event `Hspec.shouldBe` json++ Hspec.it "works with a transaction" $ do+ let event = Event.empty {Event.transaction = Text.pack "example-transaction"}+ json = [Aeson.aesonQQ| { "event_id": "00000000000000000000000000000000", "transaction": "example-transaction" } |]+ Aeson.toJSON event `Hspec.shouldBe` json++ Hspec.it "works with some transaction info" $ do+ let transactionInfo = TransactionInfo.empty {TransactionInfo.original = Text.pack "example-original"}+ event = Event.empty {Event.transactionInfo = Just transactionInfo}+ json = [Aeson.aesonQQ| { "event_id": "00000000000000000000000000000000", "transaction_info": { "original": "example-original" } } |]+ Aeson.toJSON event `Hspec.shouldBe` json++ Hspec.it "works with a type" $ do+ let event = Event.empty {Event.type_ = Just EventType.Default}+ json = [Aeson.aesonQQ| { "event_id": "00000000000000000000000000000000", "type": "default" } |]+ Aeson.toJSON event `Hspec.shouldBe` json++ Hspec.it "works with a user" $ do+ let user = User.empty {User.email = Text.pack "example-email"}+ event = Event.empty {Event.user = Just user}+ json = [Aeson.aesonQQ| { "event_id": "00000000000000000000000000000000", "user": { "email": "example-email" } } |]+ Aeson.toJSON event `Hspec.shouldBe` json++ Hspec.it "works with a version" $ do+ let event = Event.empty {Event.version = Text.pack "example-version"}+ json = [Aeson.aesonQQ| { "event_id": "00000000000000000000000000000000", "version": "example-version" } |]+ Aeson.toJSON event `Hspec.shouldBe` json++ Hspec.describe "intoRequest" $ do+ Hspec.it "sets the method" $ do+ dsn <- maybe (fail "invalid DSN") pure $ Dsn.fromUri [Uri.uri|http://public-key@sentry.test/project-id|]+ event <- Event.new+ request <- Event.intoRequest dsn event+ Client.method request `Hspec.shouldBe` Http.methodPost++ Hspec.it "sets the host" $ do+ dsn <- maybe (fail "invalid DSN") pure $ Dsn.fromUri [Uri.uri|http://public-key@sentry.test:8080/project-id|]+ event <- Event.new+ request <- Event.intoRequest dsn event+ Client.host request `Hspec.shouldBe` Text.encodeUtf8 (Text.pack "sentry.test")++ Hspec.it "sets the port" $ do+ dsn <- maybe (fail "invalid DSN") pure $ Dsn.fromUri [Uri.uri|http://public-key@sentry.test:8080/project-id|]+ event <- Event.new+ request <- Event.intoRequest dsn event+ Client.port request `Hspec.shouldBe` 8080++ Hspec.it "sets the path" $ do+ dsn <- maybe (fail "invalid DSN") pure $ Dsn.fromUri [Uri.uri|http://public-key@sentry.test/project-id|]+ event <- Event.new+ request <- Event.intoRequest dsn event+ Client.path request `Hspec.shouldBe` Text.encodeUtf8 (Text.pack "/api/project-id/store/")++ Hspec.it "handles a custom path" $ do+ dsn <- maybe (fail "invalid DSN") pure $ Dsn.fromUri [Uri.uri|http://public-key@sentry.test/custom/project-id|]+ event <- Event.new+ request <- Event.intoRequest dsn event+ Client.path request `Hspec.shouldBe` Text.encodeUtf8 (Text.pack "/custom/api/project-id/store/")++ Hspec.it "sets the body" $ do+ dsn <- maybe (fail "invalid DSN") pure $ Dsn.fromUri [Uri.uri|http://public-key@sentry.test/project-id|]+ event <- Event.new+ request <- Event.intoRequest dsn event+ case Client.requestBody request of+ Client.RequestBodyBS byteString -> byteString `Hspec.shouldBe` LazyByteString.toStrict (Aeson.encode event)+ _ -> fail "unexpected request body"++ Hspec.it "sets the content type" $ do+ dsn <- maybe (fail "invalid DSN") pure $ Dsn.fromUri [Uri.uri|http://public-key@sentry.test/project-id|]+ event <- Event.new+ request <- Event.intoRequest dsn event+ lookup Http.hContentType (Client.requestHeaders request) `Hspec.shouldSatisfy` Maybe.isJust++ Hspec.it "sets the user agent" $ do+ dsn <- maybe (fail "invalid DSN") pure $ Dsn.fromUri [Uri.uri|http://public-key@sentry.test/project-id|]+ event <- Event.new+ request <- Event.intoRequest dsn event+ lookup Http.hUserAgent (Client.requestHeaders request) `Hspec.shouldSatisfy` Maybe.isJust++ Hspec.it "sets the authorization" $ do+ dsn <- maybe (fail "invalid DSN") pure $ Dsn.fromUri [Uri.uri|http://public-key@sentry.test/project-id|]+ event <- Event.new+ request <- Event.intoRequest dsn event+ lookup Constant.xSentryAuth (Client.requestHeaders request) `Hspec.shouldSatisfy` Maybe.isJust
+ source/test-suite/Patrol/Type/EventTypeSpec.hs view
@@ -0,0 +1,32 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.EventTypeSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Patrol.Type.EventType as EventType+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.EventType" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works for Csp" $ do+ Aeson.toJSON EventType.Csp `Hspec.shouldBe` [Aeson.aesonQQ| "csp" |]++ Hspec.it "works for Default" $ do+ Aeson.toJSON EventType.Default `Hspec.shouldBe` [Aeson.aesonQQ| "default" |]++ Hspec.it "works for Error" $ do+ Aeson.toJSON EventType.Error `Hspec.shouldBe` [Aeson.aesonQQ| "error" |]++ Hspec.it "works for Expectct" $ do+ Aeson.toJSON EventType.Expectct `Hspec.shouldBe` [Aeson.aesonQQ| "expectct" |]++ Hspec.it "works for Expectstaple" $ do+ Aeson.toJSON EventType.Expectstaple `Hspec.shouldBe` [Aeson.aesonQQ| "expectstaple" |]++ Hspec.it "works for Hpkp" $ do+ Aeson.toJSON EventType.Hpkp `Hspec.shouldBe` [Aeson.aesonQQ| "hpkp" |]++ Hspec.it "works for Transaction" $ do+ Aeson.toJSON EventType.Transaction `Hspec.shouldBe` [Aeson.aesonQQ| "transaction" |]
+ source/test-suite/Patrol/Type/ExceptionSpec.hs view
@@ -0,0 +1,62 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.ExceptionSpec where++import qualified Control.Monad.Catch as Catch+import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Map as Map+import qualified Data.Text as Text+import qualified Patrol.Type.Exception as Exception+import qualified Patrol.Type.Mechanism as Mechanism+import qualified Patrol.Type.Stacktrace as Stacktrace+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.Exception" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let exception = Exception.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON exception `Hspec.shouldBe` json++ Hspec.it "works with a mechanism" $ do+ let mechanism = Mechanism.empty {Mechanism.type_ = Text.pack "example-mechanism"}+ exception = Exception.empty {Exception.mechanism = Just mechanism}+ json = [Aeson.aesonQQ| { "mechanism": { "type": "example-mechanism" } } |]+ Aeson.toJSON exception `Hspec.shouldBe` json++ Hspec.it "works with a module" $ do+ let exception = Exception.empty {Exception.module_ = Text.pack "example-module"}+ json = [Aeson.aesonQQ| { "module": "example-module" } |]+ Aeson.toJSON exception `Hspec.shouldBe` json++ Hspec.it "works with a stack trace" $ do+ let stacktrace = Stacktrace.empty {Stacktrace.registers = Map.singleton (Text.pack "example-key") $ Text.pack "example-value"}+ exception = Exception.empty {Exception.stacktrace = Just stacktrace}+ json = [Aeson.aesonQQ| { "stacktrace": { "registers": { "example-key": "example-value" } } } |]+ Aeson.toJSON exception `Hspec.shouldBe` json++ Hspec.it "works with a thread ID" $ do+ let exception = Exception.empty {Exception.threadId = Text.pack "example-thread-id"}+ json = [Aeson.aesonQQ| { "thread_id": "example-thread-id" } |]+ Aeson.toJSON exception `Hspec.shouldBe` json++ Hspec.it "works with a type" $ do+ let exception = Exception.empty {Exception.type_ = Text.pack "example-type"}+ json = [Aeson.aesonQQ| { "type": "example-type" } |]+ Aeson.toJSON exception `Hspec.shouldBe` json++ Hspec.it "works with a value" $ do+ let exception = Exception.empty {Exception.value = Text.pack "example-value"}+ json = [Aeson.aesonQQ| { "value": "example-value" } |]+ Aeson.toJSON exception `Hspec.shouldBe` json++ Hspec.describe "fromSomeException" $ do+ let exception = Exception.fromSomeException . Catch.toException $ userError "example-exception-value"++ Hspec.it "sets the type" $ do+ Exception.type_ exception `Hspec.shouldBe` Text.pack "IOException"++ Hspec.it "sets the value" $ do+ Exception.value exception `Hspec.shouldBe` Text.pack "user error (example-exception-value)"
+ source/test-suite/Patrol/Type/ExceptionsSpec.hs view
@@ -0,0 +1,24 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.ExceptionsSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Text as Text+import qualified Patrol.Type.Exception as Exception+import qualified Patrol.Type.Exceptions as Exceptions+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.Exceptions" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let exceptions = Exceptions.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON exceptions `Hspec.shouldBe` json++ Hspec.it "works with a value" $ do+ let exception = Exception.empty {Exception.type_ = Text.pack "example-type"}+ exceptions = Exceptions.empty {Exceptions.values = [exception]}+ json = [Aeson.aesonQQ| { "values": [ { "type": "example-type" } ] } |]+ Aeson.toJSON exceptions `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/FrameSpec.hs view
@@ -0,0 +1,137 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.FrameSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Map as Map+import qualified Data.Text as Text+import qualified GHC.Stack as Stack+import qualified Patrol.Type.Frame as Frame+import qualified Patrol.Type.Platform as Platform+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.Frame" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let frame = Frame.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON frame `Hspec.shouldBe` json++ Hspec.it "works with an abs path" $ do+ let frame = Frame.empty {Frame.absPath = Text.pack "example-abs-path"}+ json = [Aeson.aesonQQ| { "abs_path": "example-abs-path" } |]+ Aeson.toJSON frame `Hspec.shouldBe` json++ Hspec.it "works with an addr mode" $ do+ let frame = Frame.empty {Frame.addrMode = Text.pack "example-addr-mode"}+ json = [Aeson.aesonQQ| { "addr_mode": "example-addr-mode" } |]+ Aeson.toJSON frame `Hspec.shouldBe` json++ Hspec.it "works with a colno" $ do+ let frame = Frame.empty {Frame.colno = Just 0}+ json = [Aeson.aesonQQ| { "colno": 0 } |]+ Aeson.toJSON frame `Hspec.shouldBe` json++ Hspec.it "works with a context line" $ do+ let frame = Frame.empty {Frame.contextLine = Text.pack "example-context-line"}+ json = [Aeson.aesonQQ| { "context_line": "example-context-line" } |]+ Aeson.toJSON frame `Hspec.shouldBe` json++ Hspec.it "works with a filename" $ do+ let frame = Frame.empty {Frame.filename = Text.pack "example-filename"}+ json = [Aeson.aesonQQ| { "filename": "example-filename" } |]+ Aeson.toJSON frame `Hspec.shouldBe` json++ Hspec.it "works with a function" $ do+ let frame = Frame.empty {Frame.function = Text.pack "example-function"}+ json = [Aeson.aesonQQ| { "function": "example-function" } |]+ Aeson.toJSON frame `Hspec.shouldBe` json++ Hspec.it "works with an image addr" $ do+ let frame = Frame.empty {Frame.imageAddr = Text.pack "example-image-addr"}+ json = [Aeson.aesonQQ| { "image_addr": "example-image-addr" } |]+ Aeson.toJSON frame `Hspec.shouldBe` json++ Hspec.it "works with an in app flag" $ do+ let frame = Frame.empty {Frame.inApp = Just True}+ json = [Aeson.aesonQQ| { "in_app": true } |]+ Aeson.toJSON frame `Hspec.shouldBe` json++ Hspec.it "works with an instruction addr" $ do+ let frame = Frame.empty {Frame.instructionAddr = Text.pack "example-instruction-addr"}+ json = [Aeson.aesonQQ| { "instruction_addr": "example-instruction-addr" } |]+ Aeson.toJSON frame `Hspec.shouldBe` json++ Hspec.it "works with a lineno" $ do+ let frame = Frame.empty {Frame.lineno = Just 0}+ json = [Aeson.aesonQQ| { "lineno": 0 } |]+ Aeson.toJSON frame `Hspec.shouldBe` json++ Hspec.it "works with a module" $ do+ let frame = Frame.empty {Frame.module_ = Text.pack "example-module"}+ json = [Aeson.aesonQQ| { "module": "example-module" } |]+ Aeson.toJSON frame `Hspec.shouldBe` json++ Hspec.it "works with a package" $ do+ let frame = Frame.empty {Frame.package = Text.pack "example-package"}+ json = [Aeson.aesonQQ| { "package": "example-package" } |]+ Aeson.toJSON frame `Hspec.shouldBe` json++ Hspec.it "works with a platform" $ do+ let frame = Frame.empty {Frame.platform = Just Platform.Other}+ json = [Aeson.aesonQQ| { "platform": "other" } |]+ Aeson.toJSON frame `Hspec.shouldBe` json++ Hspec.it "works with some post context" $ do+ let frame = Frame.empty {Frame.postContext = [Text.pack "example-post-context"]}+ json = [Aeson.aesonQQ| { "post_context": [ "example-post-context" ] } |]+ Aeson.toJSON frame `Hspec.shouldBe` json++ Hspec.it "works with some pre context" $ do+ let frame = Frame.empty {Frame.preContext = [Text.pack "example-pre-context"]}+ json = [Aeson.aesonQQ| { "pre_context": [ "example-pre-context" ] } |]+ Aeson.toJSON frame `Hspec.shouldBe` json++ Hspec.it "works with a raw function" $ do+ let frame = Frame.empty {Frame.rawFunction = Text.pack "example-raw-function"}+ json = [Aeson.aesonQQ| { "raw_function": "example-raw-function" } |]+ Aeson.toJSON frame `Hspec.shouldBe` json++ Hspec.it "works with a stack start flag" $ do+ let frame = Frame.empty {Frame.stackStart = Just True}+ json = [Aeson.aesonQQ| { "stack_start": true } |]+ Aeson.toJSON frame `Hspec.shouldBe` json++ Hspec.it "works with a symbol addr" $ do+ let frame = Frame.empty {Frame.symbolAddr = Text.pack "example-symbol-addr"}+ json = [Aeson.aesonQQ| { "symbol_addr": "example-symbol-addr" } |]+ Aeson.toJSON frame `Hspec.shouldBe` json++ Hspec.it "works with some vars" $ do+ let frame = Frame.empty {Frame.vars = Map.singleton (Text.pack "example-var") Aeson.Null}+ json = [Aeson.aesonQQ| { "vars": { "example-var": null } } |]+ Aeson.toJSON frame `Hspec.shouldBe` json++ Hspec.describe "fromSrcLoc" $ do+ Hspec.it "works" $ do+ let srcLoc =+ Stack.SrcLoc+ { Stack.srcLocEndCol = 3,+ Stack.srcLocEndLine = 4,+ Stack.srcLocFile = "example-file",+ Stack.srcLocModule = "example-module",+ Stack.srcLocPackage = "example-package",+ Stack.srcLocStartCol = 1,+ Stack.srcLocStartLine = 2+ }+ frame =+ Frame.empty+ { Frame.colno = Just 1,+ Frame.filename = Text.pack "example-file",+ Frame.lineno = Just 2,+ Frame.module_ = Text.pack "example-module",+ Frame.package = Text.pack "example-package"+ }+ Frame.fromSrcLoc srcLoc `Hspec.shouldBe` frame
+ source/test-suite/Patrol/Type/GeoSpec.hs view
@@ -0,0 +1,32 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.GeoSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Text as Text+import qualified Patrol.Type.Geo as Geo+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.Geo" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let geo = Geo.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON geo `Hspec.shouldBe` json++ Hspec.it "works with a city" $ do+ let geo = Geo.empty {Geo.city = Text.pack "example-city"}+ json = [Aeson.aesonQQ| { "city": "example-city" } |]+ Aeson.toJSON geo `Hspec.shouldBe` json++ Hspec.it "works with a country code" $ do+ let geo = Geo.empty {Geo.countryCode = Text.pack "example-country-code"}+ json = [Aeson.aesonQQ| { "country_code": "example-country-code" } |]+ Aeson.toJSON geo `Hspec.shouldBe` json++ Hspec.it "works with a region" $ do+ let geo = Geo.empty {Geo.region = Text.pack "example-region"}+ json = [Aeson.aesonQQ| { "region": "example-region" } |]+ Aeson.toJSON geo `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/GpuContextSpec.hs view
@@ -0,0 +1,87 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.GpuContextSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Text as Text+import qualified Patrol.Type.GpuContext as GpuContext+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.GpuContext" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let gpuContext = GpuContext.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON gpuContext `Hspec.shouldBe` json++ Hspec.it "works with apiType" $ do+ let gpuContext = GpuContext.empty {GpuContext.apiType = Text.pack "example-apiType"}+ json = [Aeson.aesonQQ| { "api_type": "example-apiType" } |]+ Aeson.toJSON gpuContext `Hspec.shouldBe` json++ Hspec.it "works with graphicsShaderLevel" $ do+ let gpuContext = GpuContext.empty {GpuContext.graphicsShaderLevel = Text.pack "example-graphicsShaderLevel"}+ json = [Aeson.aesonQQ| { "graphics_shader_level": "example-graphicsShaderLevel" } |]+ Aeson.toJSON gpuContext `Hspec.shouldBe` json++ Hspec.it "works with id" $ do+ let gpuContext = GpuContext.empty {GpuContext.id = Aeson.Bool True}+ json = [Aeson.aesonQQ| { "id": true } |]+ Aeson.toJSON gpuContext `Hspec.shouldBe` json++ Hspec.it "works with maxTextureSize" $ do+ let gpuContext = GpuContext.empty {GpuContext.maxTextureSize = Just 0}+ json = [Aeson.aesonQQ| { "max_texture_size": 0 } |]+ Aeson.toJSON gpuContext `Hspec.shouldBe` json++ Hspec.it "works with memorySize" $ do+ let gpuContext = GpuContext.empty {GpuContext.memorySize = Just 0.1}+ json = [Aeson.aesonQQ| { "memory_size": 0.1 } |]+ Aeson.toJSON gpuContext `Hspec.shouldBe` json++ Hspec.it "works with multiThreadedRendering" $ do+ let gpuContext = GpuContext.empty {GpuContext.multiThreadedRendering = Just True}+ json = [Aeson.aesonQQ| { "multi_threaded_rendering": true } |]+ Aeson.toJSON gpuContext `Hspec.shouldBe` json++ Hspec.it "works with name" $ do+ let gpuContext = GpuContext.empty {GpuContext.name = Text.pack "example-name"}+ json = [Aeson.aesonQQ| { "name": "example-name" } |]+ Aeson.toJSON gpuContext `Hspec.shouldBe` json++ Hspec.it "works with npotSupport" $ do+ let gpuContext = GpuContext.empty {GpuContext.npotSupport = Text.pack "example-npotSupport"}+ json = [Aeson.aesonQQ| { "npot_support": "example-npotSupport" } |]+ Aeson.toJSON gpuContext `Hspec.shouldBe` json++ Hspec.it "works with supportsComputeShaders" $ do+ let gpuContext = GpuContext.empty {GpuContext.supportsComputeShaders = Just True}+ json = [Aeson.aesonQQ| { "supports_compute_shaders": true } |]+ Aeson.toJSON gpuContext `Hspec.shouldBe` json++ Hspec.it "works with supportsGeometryShaders" $ do+ let gpuContext = GpuContext.empty {GpuContext.supportsGeometryShaders = Just True}+ json = [Aeson.aesonQQ| { "supports_geometry_shaders": true } |]+ Aeson.toJSON gpuContext `Hspec.shouldBe` json++ Hspec.it "works with supportsRayTracing" $ do+ let gpuContext = GpuContext.empty {GpuContext.supportsRayTracing = Just True}+ json = [Aeson.aesonQQ| { "supports_ray_tracing": true } |]+ Aeson.toJSON gpuContext `Hspec.shouldBe` json++ Hspec.it "works with vendorId" $ do+ let gpuContext = GpuContext.empty {GpuContext.vendorId = Text.pack "example-vendorId"}+ json = [Aeson.aesonQQ| { "vendor_id": "example-vendorId" } |]+ Aeson.toJSON gpuContext `Hspec.shouldBe` json++ Hspec.it "works with vendorName" $ do+ let gpuContext = GpuContext.empty {GpuContext.vendorName = Text.pack "example-vendorName"}+ json = [Aeson.aesonQQ| { "vendor_name": "example-vendorName" } |]+ Aeson.toJSON gpuContext `Hspec.shouldBe` json++ Hspec.it "works with version" $ do+ let gpuContext = GpuContext.empty {GpuContext.version = Text.pack "example-version"}+ json = [Aeson.aesonQQ| { "version": "example-version" } |]+ Aeson.toJSON gpuContext `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/LevelSpec.hs view
@@ -0,0 +1,26 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.LevelSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Patrol.Type.Level as Level+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.Level" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works for Debug" $ do+ Aeson.toJSON Level.Debug `Hspec.shouldBe` [Aeson.aesonQQ| "debug" |]++ Hspec.it "works for Info" $ do+ Aeson.toJSON Level.Info `Hspec.shouldBe` [Aeson.aesonQQ| "info" |]++ Hspec.it "works for Warning" $ do+ Aeson.toJSON Level.Warning `Hspec.shouldBe` [Aeson.aesonQQ| "warning" |]++ Hspec.it "works for Error" $ do+ Aeson.toJSON Level.Error `Hspec.shouldBe` [Aeson.aesonQQ| "error" |]++ Hspec.it "works for Fatal" $ do+ Aeson.toJSON Level.Fatal `Hspec.shouldBe` [Aeson.aesonQQ| "fatal" |]
+ source/test-suite/Patrol/Type/LogEntrySpec.hs view
@@ -0,0 +1,32 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.LogEntrySpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Text as Text+import qualified Patrol.Type.LogEntry as LogEntry+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.LogEntry" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let logEntry = LogEntry.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON logEntry `Hspec.shouldBe` json++ Hspec.it "works with a formatted string" $ do+ let logEntry = LogEntry.empty {LogEntry.formatted = Text.pack "example-formatted"}+ json = [Aeson.aesonQQ| { "formatted": "example-formatted" } |]+ Aeson.toJSON logEntry `Hspec.shouldBe` json++ Hspec.it "works with a message" $ do+ let logEntry = LogEntry.empty {LogEntry.message = Text.pack "example-message"}+ json = [Aeson.aesonQQ| { "message": "example-message" } |]+ Aeson.toJSON logEntry `Hspec.shouldBe` json++ Hspec.it "works with some params" $ do+ let logEntry = LogEntry.empty {LogEntry.params = Aeson.Bool True}+ json = [Aeson.aesonQQ| { "params": true } |]+ Aeson.toJSON logEntry `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/MachExceptionSpec.hs view
@@ -0,0 +1,37 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.MachExceptionSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Text as Text+import qualified Patrol.Type.MachException as MachException+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.MachException" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let machException = MachException.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON machException `Hspec.shouldBe` json++ Hspec.it "works with a code" $ do+ let machException = MachException.empty {MachException.code = Just 0}+ json = [Aeson.aesonQQ| { "code": 0 } |]+ Aeson.toJSON machException `Hspec.shouldBe` json++ Hspec.it "works with an exception" $ do+ let machException = MachException.empty {MachException.exception = Just 0}+ json = [Aeson.aesonQQ| { "exception": 0 } |]+ Aeson.toJSON machException `Hspec.shouldBe` json++ Hspec.it "works with a name" $ do+ let machException = MachException.empty {MachException.name = Text.pack "example-name"}+ json = [Aeson.aesonQQ| { "name": "example-name" } |]+ Aeson.toJSON machException `Hspec.shouldBe` json++ Hspec.it "works with a subcode" $ do+ let machException = MachException.empty {MachException.subcode = Just 0}+ json = [Aeson.aesonQQ| { "subcode": 0 } |]+ Aeson.toJSON machException `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/MechanismMetaSpec.hs view
@@ -0,0 +1,47 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.MechanismMetaSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Patrol.Type.CError as CError+import qualified Patrol.Type.MachException as MachException+import qualified Patrol.Type.MechanismMeta as MechanismMeta+import qualified Patrol.Type.NsError as NsError+import qualified Patrol.Type.PosixSignal as PosixSignal+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.MechanismMeta" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let mechanismMeta = MechanismMeta.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON mechanismMeta `Hspec.shouldBe` json++ Hspec.it "works with a C error" $ do+ let cError = CError.empty {CError.number = Just 0}+ mechanismMeta = MechanismMeta.empty {MechanismMeta.errno = Just cError}+ json = [Aeson.aesonQQ| { "errno": { "number": 0 } } |]+ Aeson.toJSON mechanismMeta `Hspec.shouldBe` json++ Hspec.it "works with a mach exception" $ do+ let machException =+ MachException.empty+ { MachException.code = Just 0+ }+ mechanismMeta = MechanismMeta.empty {MechanismMeta.machException = Just machException}+ json = [Aeson.aesonQQ| { "mach_exception": { "code": 0 } } |]+ Aeson.toJSON mechanismMeta `Hspec.shouldBe` json++ Hspec.it "works with an NS error" $ do+ let nsError = NsError.empty {NsError.code = Just 0}+ mechanismMeta = MechanismMeta.empty {MechanismMeta.nsError = Just nsError}+ json = [Aeson.aesonQQ| { "ns_error": { "code": 0 } } |]+ Aeson.toJSON mechanismMeta `Hspec.shouldBe` json++ Hspec.it "works with a signal" $ do+ let posixSignal = PosixSignal.empty {PosixSignal.code = Just 0}+ mechanismMeta = MechanismMeta.empty {MechanismMeta.signal = Just posixSignal}+ json = [Aeson.aesonQQ| { "signal": { "code": 0 } } |]+ Aeson.toJSON mechanismMeta `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/MechanismSpec.hs view
@@ -0,0 +1,57 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.MechanismSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Map as Map+import qualified Data.Text as Text+import qualified Patrol.Type.CError as CError+import qualified Patrol.Type.Mechanism as Mechanism+import qualified Patrol.Type.MechanismMeta as MechanismMeta+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.Mechanism" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let mechanism = Mechanism.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON mechanism `Hspec.shouldBe` json++ Hspec.it "works with some data" $ do+ let mechanism = Mechanism.empty {Mechanism.data_ = Map.singleton (Text.pack "example-data") Aeson.Null}+ json = [Aeson.aesonQQ| { "data": { "example-data": null } } |]+ Aeson.toJSON mechanism `Hspec.shouldBe` json++ Hspec.it "works with a description" $ do+ let mechanism = Mechanism.empty {Mechanism.description = Text.pack "example-description"}+ json = [Aeson.aesonQQ| { "description": "example-description" } |]+ Aeson.toJSON mechanism `Hspec.shouldBe` json++ Hspec.it "works with a handled flag" $ do+ let mechanism = Mechanism.empty {Mechanism.handled = Just True}+ json = [Aeson.aesonQQ| { "handled": true } |]+ Aeson.toJSON mechanism `Hspec.shouldBe` json++ Hspec.it "works with a help link" $ do+ let mechanism = Mechanism.empty {Mechanism.helpLink = Text.pack "example-help-link"}+ json = [Aeson.aesonQQ| { "help_link": "example-help-link" } |]+ Aeson.toJSON mechanism `Hspec.shouldBe` json++ Hspec.it "works with some meta" $ do+ let cError = CError.empty {CError.number = Just 0}+ mechanismMeta = MechanismMeta.empty {MechanismMeta.errno = Just cError}+ mechanism = Mechanism.empty {Mechanism.meta = Just mechanismMeta}+ json = [Aeson.aesonQQ| { "meta": { "errno": { "number": 0 } } } |]+ Aeson.toJSON mechanism `Hspec.shouldBe` json++ Hspec.it "works with a synthetic flag" $ do+ let mechanism = Mechanism.empty {Mechanism.synthetic = Just True}+ json = [Aeson.aesonQQ| { "synthetic": true } |]+ Aeson.toJSON mechanism `Hspec.shouldBe` json++ Hspec.it "works with a type" $ do+ let mechanism = Mechanism.empty {Mechanism.type_ = Text.pack "example-type"}+ json = [Aeson.aesonQQ| { "type": "example-type" } |]+ Aeson.toJSON mechanism `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/NativeDebugImageSpec.hs view
@@ -0,0 +1,62 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.NativeDebugImageSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Text as Text+import qualified Patrol.Type.NativeDebugImage as NativeDebugImage+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.NativeDebugImage" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let nativeDebugImage = NativeDebugImage.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON nativeDebugImage `Hspec.shouldBe` json++ Hspec.it "works with an arch" $ do+ let nativeDebugImage = NativeDebugImage.empty {NativeDebugImage.arch = Text.pack "example-arch"}+ json = [Aeson.aesonQQ| { "arch": "example-arch" } |]+ Aeson.toJSON nativeDebugImage `Hspec.shouldBe` json++ Hspec.it "works with a code file" $ do+ let nativeDebugImage = NativeDebugImage.empty {NativeDebugImage.codeFile = Text.pack "example-code-file"}+ json = [Aeson.aesonQQ| { "code_file": "example-code-file" } |]+ Aeson.toJSON nativeDebugImage `Hspec.shouldBe` json++ Hspec.it "works with a code id" $ do+ let nativeDebugImage = NativeDebugImage.empty {NativeDebugImage.codeId = Text.pack "example-code-id"}+ json = [Aeson.aesonQQ| { "code_id": "example-code-id" } |]+ Aeson.toJSON nativeDebugImage `Hspec.shouldBe` json++ Hspec.it "works with a debug file" $ do+ let nativeDebugImage = NativeDebugImage.empty {NativeDebugImage.debugFile = Text.pack "example-debug-file"}+ json = [Aeson.aesonQQ| { "debug_file": "example-debug-file" } |]+ Aeson.toJSON nativeDebugImage `Hspec.shouldBe` json++ Hspec.it "works with a debug id" $ do+ let nativeDebugImage = NativeDebugImage.empty {NativeDebugImage.debugId = Text.pack "example-debug-id"}+ json = [Aeson.aesonQQ| { "debug_id": "example-debug-id" } |]+ Aeson.toJSON nativeDebugImage `Hspec.shouldBe` json++ Hspec.it "works with a image addr" $ do+ let nativeDebugImage = NativeDebugImage.empty {NativeDebugImage.imageAddr = Text.pack "example-image-addr"}+ json = [Aeson.aesonQQ| { "image_addr": "example-image-addr" } |]+ Aeson.toJSON nativeDebugImage `Hspec.shouldBe` json++ Hspec.it "works with a image size" $ do+ let nativeDebugImage = NativeDebugImage.empty {NativeDebugImage.imageSize = Just 0}+ json = [Aeson.aesonQQ| { "image_size": 0 } |]+ Aeson.toJSON nativeDebugImage `Hspec.shouldBe` json++ Hspec.it "works with a image vmaddr" $ do+ let nativeDebugImage = NativeDebugImage.empty {NativeDebugImage.imageVmaddr = Text.pack "example-image-vmaddr"}+ json = [Aeson.aesonQQ| { "image_vmaddr": "example-image-vmaddr" } |]+ Aeson.toJSON nativeDebugImage `Hspec.shouldBe` json++ Hspec.it "works with a type" $ do+ let nativeDebugImage = NativeDebugImage.empty {NativeDebugImage.type_ = Text.pack "example-type"}+ json = [Aeson.aesonQQ| { "type": "example-type" } |]+ Aeson.toJSON nativeDebugImage `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/NsErrorSpec.hs view
@@ -0,0 +1,27 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.NsErrorSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Text as Text+import qualified Patrol.Type.NsError as NsError+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.NsError" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let nsError = NsError.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON nsError `Hspec.shouldBe` json++ Hspec.it "works with a code" $ do+ let nsError = NsError.empty {NsError.code = Just 0}+ json = [Aeson.aesonQQ| { "code": 0 } |]+ Aeson.toJSON nsError `Hspec.shouldBe` json++ Hspec.it "works with a domain" $ do+ let nsError = NsError.empty {NsError.domain = Text.pack "example-domain"}+ json = [Aeson.aesonQQ| { "domain": "example-domain" } |]+ Aeson.toJSON nsError `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/OsContextSpec.hs view
@@ -0,0 +1,47 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.OsContextSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Text as Text+import qualified Patrol.Type.OsContext as OsContext+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.OsContext" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let osContext = OsContext.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON osContext `Hspec.shouldBe` json++ Hspec.it "works with build" $ do+ let osContext = OsContext.empty {OsContext.build = Text.pack "example-build"}+ json = [Aeson.aesonQQ| { "build": "example-build" } |]+ Aeson.toJSON osContext `Hspec.shouldBe` json++ Hspec.it "works with kernelVersion" $ do+ let osContext = OsContext.empty {OsContext.kernelVersion = Text.pack "example-kernelVersion"}+ json = [Aeson.aesonQQ| { "kernel_version": "example-kernelVersion" } |]+ Aeson.toJSON osContext `Hspec.shouldBe` json++ Hspec.it "works with name" $ do+ let osContext = OsContext.empty {OsContext.name = Text.pack "example-name"}+ json = [Aeson.aesonQQ| { "name": "example-name" } |]+ Aeson.toJSON osContext `Hspec.shouldBe` json++ Hspec.it "works with rawDescription" $ do+ let osContext = OsContext.empty {OsContext.rawDescription = Text.pack "example-rawDescription"}+ json = [Aeson.aesonQQ| { "raw_description": "example-rawDescription" } |]+ Aeson.toJSON osContext `Hspec.shouldBe` json++ Hspec.it "works with rooted" $ do+ let osContext = OsContext.empty {OsContext.rooted = Just True}+ json = [Aeson.aesonQQ| { "rooted": true } |]+ Aeson.toJSON osContext `Hspec.shouldBe` json++ Hspec.it "works with version" $ do+ let osContext = OsContext.empty {OsContext.version = Text.pack "example-version"}+ json = [Aeson.aesonQQ| { "version": "example-version" } |]+ Aeson.toJSON osContext `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/PlatformSpec.hs view
@@ -0,0 +1,68 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.PlatformSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Patrol.Type.Platform as Platform+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.Platform" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works for As3" $ do+ Aeson.toJSON Platform.As3 `Hspec.shouldBe` [Aeson.aesonQQ| "as3" |]++ Hspec.it "works for C" $ do+ Aeson.toJSON Platform.C `Hspec.shouldBe` [Aeson.aesonQQ| "c" |]++ Hspec.it "works for Cfml" $ do+ Aeson.toJSON Platform.Cfml `Hspec.shouldBe` [Aeson.aesonQQ| "cfml" |]++ Hspec.it "works for Cocoa" $ do+ Aeson.toJSON Platform.Cocoa `Hspec.shouldBe` [Aeson.aesonQQ| "cocoa" |]++ Hspec.it "works for Csharp" $ do+ Aeson.toJSON Platform.Csharp `Hspec.shouldBe` [Aeson.aesonQQ| "csharp" |]++ Hspec.it "works for Elixir" $ do+ Aeson.toJSON Platform.Elixir `Hspec.shouldBe` [Aeson.aesonQQ| "elixir" |]++ Hspec.it "works for Haskell" $ do+ Aeson.toJSON Platform.Haskell `Hspec.shouldBe` [Aeson.aesonQQ| "haskell" |]++ Hspec.it "works for Go" $ do+ Aeson.toJSON Platform.Go `Hspec.shouldBe` [Aeson.aesonQQ| "go" |]++ Hspec.it "works for Groovy" $ do+ Aeson.toJSON Platform.Groovy `Hspec.shouldBe` [Aeson.aesonQQ| "groovy" |]++ Hspec.it "works for Java" $ do+ Aeson.toJSON Platform.Java `Hspec.shouldBe` [Aeson.aesonQQ| "java" |]++ Hspec.it "works for Javascript" $ do+ Aeson.toJSON Platform.Javascript `Hspec.shouldBe` [Aeson.aesonQQ| "javascript" |]++ Hspec.it "works for Native" $ do+ Aeson.toJSON Platform.Native `Hspec.shouldBe` [Aeson.aesonQQ| "native" |]++ Hspec.it "works for Node" $ do+ Aeson.toJSON Platform.Node `Hspec.shouldBe` [Aeson.aesonQQ| "node" |]++ Hspec.it "works for Objc" $ do+ Aeson.toJSON Platform.Objc `Hspec.shouldBe` [Aeson.aesonQQ| "objc" |]++ Hspec.it "works for Other" $ do+ Aeson.toJSON Platform.Other `Hspec.shouldBe` [Aeson.aesonQQ| "other" |]++ Hspec.it "works for Perl" $ do+ Aeson.toJSON Platform.Perl `Hspec.shouldBe` [Aeson.aesonQQ| "perl" |]++ Hspec.it "works for Php" $ do+ Aeson.toJSON Platform.Php `Hspec.shouldBe` [Aeson.aesonQQ| "php" |]++ Hspec.it "works for Python" $ do+ Aeson.toJSON Platform.Python `Hspec.shouldBe` [Aeson.aesonQQ| "python" |]++ Hspec.it "works for Ruby" $ do+ Aeson.toJSON Platform.Ruby `Hspec.shouldBe` [Aeson.aesonQQ| "ruby" |]
+ source/test-suite/Patrol/Type/PosixSignalSpec.hs view
@@ -0,0 +1,37 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.PosixSignalSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Text as Text+import qualified Patrol.Type.PosixSignal as PosixSignal+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.PosixSignal" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let posixSignal = PosixSignal.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON posixSignal `Hspec.shouldBe` json++ Hspec.it "works with a code" $ do+ let posixSignal = PosixSignal.empty {PosixSignal.code = Just 0}+ json = [Aeson.aesonQQ| { "code": 0 } |]+ Aeson.toJSON posixSignal `Hspec.shouldBe` json++ Hspec.it "works with a code name" $ do+ let posixSignal = PosixSignal.empty {PosixSignal.codeName = Text.pack "example-code-name"}+ json = [Aeson.aesonQQ| { "code_name": "example-code-name" } |]+ Aeson.toJSON posixSignal `Hspec.shouldBe` json++ Hspec.it "works with a name" $ do+ let posixSignal = PosixSignal.empty {PosixSignal.name = Text.pack "example-name"}+ json = [Aeson.aesonQQ| { "name": "example-name" } |]+ Aeson.toJSON posixSignal `Hspec.shouldBe` json++ Hspec.it "works with a number" $ do+ let posixSignal = PosixSignal.empty {PosixSignal.number = Just 0}+ json = [Aeson.aesonQQ| { "number": 0 } |]+ Aeson.toJSON posixSignal `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/ProguardDebugImageSpec.hs view
@@ -0,0 +1,22 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.ProguardDebugImageSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Text as Text+import qualified Patrol.Type.ProguardDebugImage as ProguardDebugImage+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.ProguardDebugImage" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let proguardDebugImage = ProguardDebugImage.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON proguardDebugImage `Hspec.shouldBe` json++ Hspec.it "works with a UUID" $ do+ let proguardDebugImage = ProguardDebugImage.empty {ProguardDebugImage.uuid = Text.pack "example-uuid"}+ json = [Aeson.aesonQQ| { "uuid": "example-uuid" } |]+ Aeson.toJSON proguardDebugImage `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/RequestSpec.hs view
@@ -0,0 +1,63 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.RequestSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Map as Map+import qualified Data.Text as Text+import qualified Patrol.Type.Request as Request+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.Request" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let request = Request.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON request `Hspec.shouldBe` json++ Hspec.it "works with a cookie" $ do+ let request = Request.empty {Request.cookies = Map.singleton (Text.pack "example-key") $ Text.pack "example-value"}+ json = [Aeson.aesonQQ| { "cookies": { "example-key": "example-value" } } |]+ Aeson.toJSON request `Hspec.shouldBe` json++ Hspec.it "works with some data" $ do+ let request = Request.empty {Request.data_ = Aeson.Bool True}+ json = [Aeson.aesonQQ| { "data": true } |]+ Aeson.toJSON request `Hspec.shouldBe` json++ Hspec.it "works with an env" $ do+ let request = Request.empty {Request.env = Map.singleton (Text.pack "example-key") $ Aeson.Bool True}+ json = [Aeson.aesonQQ| { "env": { "example-key": true } } |]+ Aeson.toJSON request `Hspec.shouldBe` json++ Hspec.it "works with a fragment" $ do+ let request = Request.empty {Request.fragment = Text.pack "example-fragment"}+ json = [Aeson.aesonQQ| { "fragment": "example-fragment" } |]+ Aeson.toJSON request `Hspec.shouldBe` json++ Hspec.it "works with a header" $ do+ let request = Request.empty {Request.headers = Map.singleton (Text.pack "example-key") $ Text.pack "example-value"}+ json = [Aeson.aesonQQ| { "headers": { "example-key": "example-value" } } |]+ Aeson.toJSON request `Hspec.shouldBe` json++ Hspec.it "works with an inferred content type" $ do+ let request = Request.empty {Request.inferredContentType = Text.pack "example-inferred-content-type"}+ json = [Aeson.aesonQQ| { "inferred_content_type": "example-inferred-content-type" } |]+ Aeson.toJSON request `Hspec.shouldBe` json++ Hspec.it "works with a method" $ do+ let request = Request.empty {Request.method = Text.pack "example-method"}+ json = [Aeson.aesonQQ| { "method": "example-method" } |]+ Aeson.toJSON request `Hspec.shouldBe` json++ Hspec.it "works with a query string" $ do+ let request = Request.empty {Request.queryString = Map.singleton (Text.pack "example-key") $ Text.pack "example-value"}+ json = [Aeson.aesonQQ| { "query_string": { "example-key": "example-value" } } |]+ Aeson.toJSON request `Hspec.shouldBe` json++ Hspec.it "works with a URL" $ do+ let request = Request.empty {Request.url = Text.pack "example-url"}+ json = [Aeson.aesonQQ| { "url": "example-url" } |]+ Aeson.toJSON request `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/ResponseSpec.hs view
@@ -0,0 +1,24 @@+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE TypeApplications #-}++module Patrol.Type.ResponseSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.UUID as Uuid+import qualified Patrol.Type.EventId as EventId+import qualified Patrol.Type.Response as Response+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.Response" $ do+ Hspec.describe "FromJSON" $ do+ Hspec.it "works" $ do+ let json = [Aeson.aesonQQ| { "id": "00112233445566778899aabbccddeeff" } |]+ eventId = EventId.fromUuid $ Uuid.fromWords64 0x0011223344556677 0x8899aabbccddeeff+ response = Response.Response {Response.id = eventId}+ Aeson.fromJSON json `Hspec.shouldBe` Aeson.Success response++ Hspec.it "fails with the wrong type" $ do+ let json = [Aeson.aesonQQ| null |]+ Aeson.fromJSON @Response.Response json `Hspec.shouldBe` Aeson.Error "parsing Response failed, expected Object, but encountered Null"
+ source/test-suite/Patrol/Type/RuntimeContextSpec.hs view
@@ -0,0 +1,37 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.RuntimeContextSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Text as Text+import qualified Patrol.Type.RuntimeContext as RuntimeContext+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.RuntimeContext" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let runtimeContext = RuntimeContext.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON runtimeContext `Hspec.shouldBe` json++ Hspec.it "works with build" $ do+ let runtimeContext = RuntimeContext.empty {RuntimeContext.build = Text.pack "example-build"}+ json = [Aeson.aesonQQ| { "build": "example-build" } |]+ Aeson.toJSON runtimeContext `Hspec.shouldBe` json++ Hspec.it "works with name" $ do+ let runtimeContext = RuntimeContext.empty {RuntimeContext.name = Text.pack "example-name"}+ json = [Aeson.aesonQQ| { "name": "example-name" } |]+ Aeson.toJSON runtimeContext `Hspec.shouldBe` json++ Hspec.it "works with rawDescription" $ do+ let runtimeContext = RuntimeContext.empty {RuntimeContext.rawDescription = Text.pack "example-rawDescription"}+ json = [Aeson.aesonQQ| { "raw_description": "example-rawDescription" } |]+ Aeson.toJSON runtimeContext `Hspec.shouldBe` json++ Hspec.it "works with version" $ do+ let runtimeContext = RuntimeContext.empty {RuntimeContext.version = Text.pack "example-version"}+ json = [Aeson.aesonQQ| { "version": "example-version" } |]+ Aeson.toJSON runtimeContext `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/SpanStatusSpec.hs view
@@ -0,0 +1,62 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.SpanStatusSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Patrol.Type.SpanStatus as SpanStatus+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.SpanStatus" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works for Aborted" $ do+ Aeson.toJSON SpanStatus.Aborted `Hspec.shouldBe` [Aeson.aesonQQ| "aborted" |]++ Hspec.it "works for AlreadyExists" $ do+ Aeson.toJSON SpanStatus.AlreadyExists `Hspec.shouldBe` [Aeson.aesonQQ| "already_exists" |]++ Hspec.it "works for Cancelled" $ do+ Aeson.toJSON SpanStatus.Cancelled `Hspec.shouldBe` [Aeson.aesonQQ| "cancelled" |]++ Hspec.it "works for DataLoss" $ do+ Aeson.toJSON SpanStatus.DataLoss `Hspec.shouldBe` [Aeson.aesonQQ| "data_loss" |]++ Hspec.it "works for DeadlineExceeded" $ do+ Aeson.toJSON SpanStatus.DeadlineExceeded `Hspec.shouldBe` [Aeson.aesonQQ| "deadline_exceeded" |]++ Hspec.it "works for FailedPrecondition" $ do+ Aeson.toJSON SpanStatus.FailedPrecondition `Hspec.shouldBe` [Aeson.aesonQQ| "failed_precondition" |]++ Hspec.it "works for InternalError" $ do+ Aeson.toJSON SpanStatus.InternalError `Hspec.shouldBe` [Aeson.aesonQQ| "internal_error" |]++ Hspec.it "works for InvalidArgument" $ do+ Aeson.toJSON SpanStatus.InvalidArgument `Hspec.shouldBe` [Aeson.aesonQQ| "invalid_argument" |]++ Hspec.it "works for NotFound" $ do+ Aeson.toJSON SpanStatus.NotFound `Hspec.shouldBe` [Aeson.aesonQQ| "not_found" |]++ Hspec.it "works for Ok" $ do+ Aeson.toJSON SpanStatus.Ok `Hspec.shouldBe` [Aeson.aesonQQ| "ok" |]++ Hspec.it "works for OutOfRange" $ do+ Aeson.toJSON SpanStatus.OutOfRange `Hspec.shouldBe` [Aeson.aesonQQ| "out_of_range" |]++ Hspec.it "works for PermissionDenied" $ do+ Aeson.toJSON SpanStatus.PermissionDenied `Hspec.shouldBe` [Aeson.aesonQQ| "permission_denied" |]++ Hspec.it "works for ResourceExhausted" $ do+ Aeson.toJSON SpanStatus.ResourceExhausted `Hspec.shouldBe` [Aeson.aesonQQ| "resource_exhausted" |]++ Hspec.it "works for Unauthenticated" $ do+ Aeson.toJSON SpanStatus.Unauthenticated `Hspec.shouldBe` [Aeson.aesonQQ| "unauthenticated" |]++ Hspec.it "works for Unavailable" $ do+ Aeson.toJSON SpanStatus.Unavailable `Hspec.shouldBe` [Aeson.aesonQQ| "unavailable" |]++ Hspec.it "works for Unimplemented" $ do+ Aeson.toJSON SpanStatus.Unimplemented `Hspec.shouldBe` [Aeson.aesonQQ| "unimplemented" |]++ Hspec.it "works for Unknown" $ do+ Aeson.toJSON SpanStatus.Unknown `Hspec.shouldBe` [Aeson.aesonQQ| "unknown" |]
+ source/test-suite/Patrol/Type/StacktraceSpec.hs view
@@ -0,0 +1,102 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.StacktraceSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Map as Map+import qualified Data.Text as Text+import qualified GHC.Stack as Stack+import qualified Patrol.Type.Frame as Frame+import qualified Patrol.Type.Stacktrace as Stacktrace+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.Stacktrace" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let stacktrace = Stacktrace.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON stacktrace `Hspec.shouldBe` json++ Hspec.it "works with a frame" $ do+ let frame = Frame.empty+ stacktrace = Stacktrace.empty {Stacktrace.frames = [frame]}+ json = [Aeson.aesonQQ| { "frames": [ {} ] } |]+ Aeson.toJSON stacktrace `Hspec.shouldBe` json++ Hspec.it "works with some registers" $ do+ let stacktrace = Stacktrace.empty {Stacktrace.registers = Map.singleton (Text.pack "example-key") $ Text.pack "example-value"}+ json = [Aeson.aesonQQ| { "registers": { "example-key": "example-value" } } |]+ Aeson.toJSON stacktrace `Hspec.shouldBe` json++ Hspec.describe "fromCallStack" $ do+ Hspec.it "works with an empty call stack" $ do+ let callStack = Stack.emptyCallStack+ stacktrace = Stacktrace.empty+ Stacktrace.fromCallStack callStack `Hspec.shouldBe` stacktrace++ Hspec.it "works with a single call site" $ do+ let emptySrcLoc =+ Stack.SrcLoc+ { Stack.srcLocEndCol = 0,+ Stack.srcLocEndLine = 0,+ Stack.srcLocFile = "",+ Stack.srcLocModule = "",+ Stack.srcLocPackage = "",+ Stack.srcLocStartCol = 0,+ Stack.srcLocStartLine = 0+ }+ callStack =+ Stack.fromCallSiteList+ [ ("example-function", emptySrcLoc)+ ]+ frame =+ (Frame.fromSrcLoc emptySrcLoc)+ { Frame.function = Text.pack "example-function"+ }+ stacktrace =+ Stacktrace.empty+ { Stacktrace.frames = [frame]+ }+ Stacktrace.fromCallStack callStack `Hspec.shouldBe` stacktrace++ Hspec.it "works with two call sites" $ do+ let srcLoc1 =+ Stack.SrcLoc+ { Stack.srcLocEndCol = 1,+ Stack.srcLocEndLine = 1,+ Stack.srcLocFile = "example-file-1",+ Stack.srcLocModule = "example-module-1",+ Stack.srcLocPackage = "example-package-1",+ Stack.srcLocStartCol = 1,+ Stack.srcLocStartLine = 1+ }+ srcLoc2 =+ Stack.SrcLoc+ { Stack.srcLocEndCol = 2,+ Stack.srcLocEndLine = 2,+ Stack.srcLocFile = "example-file-2",+ Stack.srcLocModule = "example-module-2",+ Stack.srcLocPackage = "example-package-2",+ Stack.srcLocStartCol = 2,+ Stack.srcLocStartLine = 2+ }+ callStack =+ Stack.fromCallSiteList+ [ ("example-function-1", srcLoc1),+ ("example-function-2", srcLoc2)+ ]+ frame1 =+ (Frame.fromSrcLoc srcLoc1)+ { Frame.function = Text.pack "example-function-1"+ }+ frame2 =+ (Frame.fromSrcLoc srcLoc2)+ { Frame.function = Text.pack "example-function-2"+ }+ stacktrace =+ Stacktrace.empty+ { Stacktrace.frames = [frame2, frame1]+ }+ Stacktrace.fromCallStack callStack `Hspec.shouldBe` stacktrace
+ source/test-suite/Patrol/Type/SystemSdkInfoSpec.hs view
@@ -0,0 +1,37 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.SystemSdkInfoSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Text as Text+import qualified Patrol.Type.SystemSdkInfo as SystemSdkInfo+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.SystemSdkInfo" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let systemSdkInfo = SystemSdkInfo.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON systemSdkInfo `Hspec.shouldBe` json++ Hspec.it "works with an SDK name" $ do+ let systemSdkInfo = SystemSdkInfo.empty {SystemSdkInfo.sdkName = Text.pack "example-sdk-name"}+ json = [Aeson.aesonQQ| { "sdk_name": "example-sdk-name" } |]+ Aeson.toJSON systemSdkInfo `Hspec.shouldBe` json++ Hspec.it "works with a major version number" $ do+ let systemSdkInfo = SystemSdkInfo.empty {SystemSdkInfo.versionMajor = Just 0}+ json = [Aeson.aesonQQ| { "version_major": 0 } |]+ Aeson.toJSON systemSdkInfo `Hspec.shouldBe` json++ Hspec.it "works with a minor version number" $ do+ let systemSdkInfo = SystemSdkInfo.empty {SystemSdkInfo.versionMinor = Just 0}+ json = [Aeson.aesonQQ| { "version_minor": 0 } |]+ Aeson.toJSON systemSdkInfo `Hspec.shouldBe` json++ Hspec.it "works with a patch version number" $ do+ let systemSdkInfo = SystemSdkInfo.empty {SystemSdkInfo.versionPatchlevel = Just 0}+ json = [Aeson.aesonQQ| { "version_patchlevel": 0 } |]+ Aeson.toJSON systemSdkInfo `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/ThreadSpec.hs view
@@ -0,0 +1,45 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.ThreadSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Map as Map+import qualified Data.Text as Text+import qualified Patrol.Type.Stacktrace as Stacktrace+import qualified Patrol.Type.Thread as Thread+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.Thread" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let thread = Thread.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON thread `Hspec.shouldBe` json++ Hspec.it "works with a crashed flag" $ do+ let thread = Thread.empty {Thread.crashed = Just True}+ json = [Aeson.aesonQQ| { "crashed": true } |]+ Aeson.toJSON thread `Hspec.shouldBe` json++ Hspec.it "works with a current flag" $ do+ let thread = Thread.empty {Thread.current = Just True}+ json = [Aeson.aesonQQ| { "current": true } |]+ Aeson.toJSON thread `Hspec.shouldBe` json++ Hspec.it "works with an ID" $ do+ let thread = Thread.empty {Thread.id = Text.pack "example-id"}+ json = [Aeson.aesonQQ| { "id": "example-id" } |]+ Aeson.toJSON thread `Hspec.shouldBe` json++ Hspec.it "works with a name" $ do+ let thread = Thread.empty {Thread.name = Text.pack "example-name"}+ json = [Aeson.aesonQQ| { "name": "example-name" } |]+ Aeson.toJSON thread `Hspec.shouldBe` json++ Hspec.it "works with a stack trace" $ do+ let stacktrace = Stacktrace.empty {Stacktrace.registers = Map.singleton (Text.pack "example-key") $ Text.pack "example-value"}+ thread = Thread.empty {Thread.stacktrace = Just stacktrace}+ json = [Aeson.aesonQQ| { "stacktrace": { "registers": { "example-key": "example-value" } } } |]+ Aeson.toJSON thread `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/ThreadsSpec.hs view
@@ -0,0 +1,23 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.ThreadsSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Patrol.Type.Thread as Thread+import qualified Patrol.Type.Threads as Threads+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.Threads" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let threads = Threads.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON threads `Hspec.shouldBe` json++ Hspec.it "works with a value" $ do+ let thread = Thread.empty {Thread.crashed = Just True}+ threads = Threads.empty {Threads.values = [thread]}+ json = [Aeson.aesonQQ| { "values": [ { "crashed": true } ] } |]+ Aeson.toJSON threads `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/TraceContextSpec.hs view
@@ -0,0 +1,48 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.TraceContextSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Text as Text+import qualified Patrol.Type.SpanStatus as SpanStatus+import qualified Patrol.Type.TraceContext as TraceContext+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.TraceContext" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let traceContext = TraceContext.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON traceContext `Hspec.shouldBe` json++ Hspec.it "works with exclusiveTime" $ do+ let traceContext = TraceContext.empty {TraceContext.exclusiveTime = Just 0}+ json = [Aeson.aesonQQ| { "exclusive_time": 0 } |]+ Aeson.toJSON traceContext `Hspec.shouldBe` json++ Hspec.it "works with op" $ do+ let traceContext = TraceContext.empty {TraceContext.op = Text.pack "example-op"}+ json = [Aeson.aesonQQ| { "op": "example-op" } |]+ Aeson.toJSON traceContext `Hspec.shouldBe` json++ Hspec.it "works with parentSpanId" $ do+ let traceContext = TraceContext.empty {TraceContext.parentSpanId = Text.pack "example-parentSpanId"}+ json = [Aeson.aesonQQ| { "parent_span_id": "example-parentSpanId" } |]+ Aeson.toJSON traceContext `Hspec.shouldBe` json++ Hspec.it "works with spanId" $ do+ let traceContext = TraceContext.empty {TraceContext.spanId = Text.pack "example-spanId"}+ json = [Aeson.aesonQQ| { "span_id": "example-spanId" } |]+ Aeson.toJSON traceContext `Hspec.shouldBe` json++ Hspec.it "works with status" $ do+ let traceContext = TraceContext.empty {TraceContext.status = Just SpanStatus.Unknown}+ json = [Aeson.aesonQQ| { "status": "unknown" } |]+ Aeson.toJSON traceContext `Hspec.shouldBe` json++ Hspec.it "works with traceId" $ do+ let traceContext = TraceContext.empty {TraceContext.traceId = Text.pack "example-traceId"}+ json = [Aeson.aesonQQ| { "trace_id": "example-traceId" } |]+ Aeson.toJSON traceContext `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/TransactionInfoSpec.hs view
@@ -0,0 +1,28 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.TransactionInfoSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Text as Text+import qualified Patrol.Type.TransactionInfo as TransactionInfo+import qualified Patrol.Type.TransactionSource as TransactionSource+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.TransactionInfo" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let transactionInfo = TransactionInfo.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON transactionInfo `Hspec.shouldBe` json++ Hspec.it "works with an original" $ do+ let transactionInfo = TransactionInfo.empty {TransactionInfo.original = Text.pack "example-original"}+ json = [Aeson.aesonQQ| { "original": "example-original" } |]+ Aeson.toJSON transactionInfo `Hspec.shouldBe` json++ Hspec.it "works with a source" $ do+ let transactionInfo = TransactionInfo.empty {TransactionInfo.source = Just TransactionSource.Unknown}+ json = [Aeson.aesonQQ| { "source": "unknown" } |]+ Aeson.toJSON transactionInfo `Hspec.shouldBe` json
+ source/test-suite/Patrol/Type/TransactionSourceSpec.hs view
@@ -0,0 +1,32 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.TransactionSourceSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Patrol.Type.TransactionSource as TransactionSource+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.TransactionSource" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works for Component" $ do+ Aeson.toJSON TransactionSource.Component `Hspec.shouldBe` [Aeson.aesonQQ| "component" |]++ Hspec.it "works for Custom" $ do+ Aeson.toJSON TransactionSource.Custom `Hspec.shouldBe` [Aeson.aesonQQ| "custom" |]++ Hspec.it "works for Route" $ do+ Aeson.toJSON TransactionSource.Route `Hspec.shouldBe` [Aeson.aesonQQ| "route" |]++ Hspec.it "works for Task" $ do+ Aeson.toJSON TransactionSource.Task `Hspec.shouldBe` [Aeson.aesonQQ| "task" |]++ Hspec.it "works for Url" $ do+ Aeson.toJSON TransactionSource.Url `Hspec.shouldBe` [Aeson.aesonQQ| "url" |]++ Hspec.it "works for Unknown" $ do+ Aeson.toJSON TransactionSource.Unknown `Hspec.shouldBe` [Aeson.aesonQQ| "unknown" |]++ Hspec.it "works for View" $ do+ Aeson.toJSON TransactionSource.View `Hspec.shouldBe` [Aeson.aesonQQ| "view" |]
+ source/test-suite/Patrol/Type/UserSpec.hs view
@@ -0,0 +1,60 @@+{-# LANGUAGE QuasiQuotes #-}++module Patrol.Type.UserSpec where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.QQ.Simple as Aeson+import qualified Data.Map as Map+import qualified Data.Text as Text+import qualified Patrol.Type.Geo as Geo+import qualified Patrol.Type.User as User+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "Patrol.Type.User" $ do+ Hspec.describe "ToJSON" $ do+ Hspec.it "works" $ do+ let user = User.empty+ json = [Aeson.aesonQQ| {} |]+ Aeson.toJSON user `Hspec.shouldBe` json++ Hspec.it "works with some data" $ do+ let user = User.empty {User.data_ = Map.singleton (Text.pack "example-data") (Aeson.Bool True)}+ json = [Aeson.aesonQQ| { "data": { "example-data": true } } |]+ Aeson.toJSON user `Hspec.shouldBe` json++ Hspec.it "works with an email" $ do+ let user = User.empty {User.email = Text.pack "example-email"}+ json = [Aeson.aesonQQ| { "email": "example-email" } |]+ Aeson.toJSON user `Hspec.shouldBe` json++ Hspec.it "works with a geo" $ do+ let geo = Geo.empty {Geo.city = Text.pack "example-city"}+ user = User.empty {User.geo = Just geo}+ json = [Aeson.aesonQQ| { "geo": { "city": "example-city" } } |]+ Aeson.toJSON user `Hspec.shouldBe` json++ Hspec.it "works with an id" $ do+ let user = User.empty {User.id = Text.pack "example-id"}+ json = [Aeson.aesonQQ| { "id": "example-id" } |]+ Aeson.toJSON user `Hspec.shouldBe` json++ Hspec.it "works with an IP address" $ do+ let user = User.empty {User.ipAddress = Text.pack "example-ip-address"}+ json = [Aeson.aesonQQ| { "ip_address": "example-ip-address" } |]+ Aeson.toJSON user `Hspec.shouldBe` json++ Hspec.it "works with a name" $ do+ let user = User.empty {User.name = Text.pack "example-name"}+ json = [Aeson.aesonQQ| { "name": "example-name" } |]+ Aeson.toJSON user `Hspec.shouldBe` json++ Hspec.it "works with a segment" $ do+ let user = User.empty {User.segment = Text.pack "example-segment"}+ json = [Aeson.aesonQQ| { "segment": "example-segment" } |]+ Aeson.toJSON user `Hspec.shouldBe` json++ Hspec.it "works with a username" $ do+ let user = User.empty {User.username = Text.pack "example-username"}+ json = [Aeson.aesonQQ| { "username": "example-username" } |]+ Aeson.toJSON user `Hspec.shouldBe` json
+ source/test-suite/PatrolSpec.hs view
@@ -0,0 +1,108 @@+module PatrolSpec where++import qualified Patrol.ClientSpec+import qualified Patrol.ConstantSpec+import qualified Patrol.Extra.AesonSpec+import qualified Patrol.Extra.ListSpec+import qualified Patrol.Type.AppContextSpec+import qualified Patrol.Type.AppleDebugImageSpec+import qualified Patrol.Type.BreadcrumbSpec+import qualified Patrol.Type.BreadcrumbTypeSpec+import qualified Patrol.Type.BreadcrumbsSpec+import qualified Patrol.Type.BrowserContextSpec+import qualified Patrol.Type.CErrorSpec+import qualified Patrol.Type.ClientSdkInfoSpec+import qualified Patrol.Type.ClientSdkPackageSpec+import qualified Patrol.Type.ContextSpec+import qualified Patrol.Type.DebugImageSpec+import qualified Patrol.Type.DebugMetaSpec+import qualified Patrol.Type.DeviceContextSpec+import qualified Patrol.Type.DsnSpec+import qualified Patrol.Type.ErrorTypeSpec+import qualified Patrol.Type.EventIdSpec+import qualified Patrol.Type.EventProcessingErrorSpec+import qualified Patrol.Type.EventSpec+import qualified Patrol.Type.EventTypeSpec+import qualified Patrol.Type.ExceptionSpec+import qualified Patrol.Type.ExceptionsSpec+import qualified Patrol.Type.FrameSpec+import qualified Patrol.Type.GeoSpec+import qualified Patrol.Type.GpuContextSpec+import qualified Patrol.Type.LevelSpec+import qualified Patrol.Type.LogEntrySpec+import qualified Patrol.Type.MachExceptionSpec+import qualified Patrol.Type.MechanismMetaSpec+import qualified Patrol.Type.MechanismSpec+import qualified Patrol.Type.NativeDebugImageSpec+import qualified Patrol.Type.NsErrorSpec+import qualified Patrol.Type.OsContextSpec+import qualified Patrol.Type.PlatformSpec+import qualified Patrol.Type.PosixSignalSpec+import qualified Patrol.Type.ProguardDebugImageSpec+import qualified Patrol.Type.RequestSpec+import qualified Patrol.Type.ResponseSpec+import qualified Patrol.Type.RuntimeContextSpec+import qualified Patrol.Type.SpanStatusSpec+import qualified Patrol.Type.StacktraceSpec+import qualified Patrol.Type.SystemSdkInfoSpec+import qualified Patrol.Type.ThreadSpec+import qualified Patrol.Type.ThreadsSpec+import qualified Patrol.Type.TraceContextSpec+import qualified Patrol.Type.TransactionInfoSpec+import qualified Patrol.Type.TransactionSourceSpec+import qualified Patrol.Type.UserSpec+import qualified Test.Hspec as Hspec++spec :: Hspec.Spec+spec = do+ Patrol.ClientSpec.spec+ Patrol.ConstantSpec.spec+ Patrol.Extra.AesonSpec.spec+ Patrol.Extra.ListSpec.spec+ Patrol.Type.AppContextSpec.spec+ Patrol.Type.AppleDebugImageSpec.spec+ Patrol.Type.BreadcrumbSpec.spec+ Patrol.Type.BreadcrumbsSpec.spec+ Patrol.Type.BreadcrumbTypeSpec.spec+ Patrol.Type.BrowserContextSpec.spec+ Patrol.Type.CErrorSpec.spec+ Patrol.Type.ClientSdkInfoSpec.spec+ Patrol.Type.ClientSdkPackageSpec.spec+ Patrol.Type.ContextSpec.spec+ Patrol.Type.DebugImageSpec.spec+ Patrol.Type.DebugMetaSpec.spec+ Patrol.Type.DeviceContextSpec.spec+ Patrol.Type.DsnSpec.spec+ Patrol.Type.ErrorTypeSpec.spec+ Patrol.Type.EventIdSpec.spec+ Patrol.Type.EventProcessingErrorSpec.spec+ Patrol.Type.EventSpec.spec+ Patrol.Type.EventTypeSpec.spec+ Patrol.Type.ExceptionSpec.spec+ Patrol.Type.ExceptionsSpec.spec+ Patrol.Type.FrameSpec.spec+ Patrol.Type.GeoSpec.spec+ Patrol.Type.GpuContextSpec.spec+ Patrol.Type.LevelSpec.spec+ Patrol.Type.LogEntrySpec.spec+ Patrol.Type.MachExceptionSpec.spec+ Patrol.Type.MechanismMetaSpec.spec+ Patrol.Type.MechanismSpec.spec+ Patrol.Type.NativeDebugImageSpec.spec+ Patrol.Type.NsErrorSpec.spec+ Patrol.Type.OsContextSpec.spec+ Patrol.Type.PlatformSpec.spec+ Patrol.Type.PosixSignalSpec.spec+ Patrol.Type.ProguardDebugImageSpec.spec+ Patrol.Type.RequestSpec.spec+ Patrol.Type.ResponseSpec.spec+ Patrol.Type.RuntimeContextSpec.spec+ Patrol.Type.SpanStatusSpec.spec+ Patrol.Type.StacktraceSpec.spec+ Patrol.Type.SystemSdkInfoSpec.spec+ Patrol.Type.ThreadSpec.spec+ Patrol.Type.ThreadsSpec.spec+ Patrol.Type.TraceContextSpec.spec+ Patrol.Type.TransactionInfoSpec.spec+ Patrol.Type.TransactionSourceSpec.spec+ Patrol.Type.UserSpec.spec
− src/lib/Patrol.hs
@@ -1,28 +0,0 @@--- | <https://develop.sentry.dev/sdk/>-module Patrol- ( Dsn.Dsn- , Event.Event- , EventId.EventId- , Exception.Exception- , Frame.Frame- , Level.Level- , Platform.Platform- , Request.Request- , Response.Response- , StackTrace.StackTrace- , Timestamp.Timestamp- , User.User- ) where--import qualified Patrol.Type.Dsn as Dsn-import qualified Patrol.Type.Event as Event-import qualified Patrol.Type.EventId as EventId-import qualified Patrol.Type.Exception as Exception-import qualified Patrol.Type.Frame as Frame-import qualified Patrol.Type.Level as Level-import qualified Patrol.Type.Platform as Platform-import qualified Patrol.Type.Request as Request-import qualified Patrol.Type.Response as Response-import qualified Patrol.Type.StackTrace as StackTrace-import qualified Patrol.Type.Timestamp as Timestamp-import qualified Patrol.Type.User as User
− src/lib/Patrol/Client.hs
@@ -1,63 +0,0 @@-module Patrol.Client- ( store- ) where--import qualified Data.Aeson as Aeson-import qualified Data.ByteString as ByteString-import qualified Data.CaseInsensitive as CI-import qualified Data.Maybe as Maybe-import qualified Data.Text as Text-import qualified Data.Text.Encoding as Text-import qualified Data.Time as Time-import qualified Data.Version as Version-import qualified Network.HTTP.Client as Client-import qualified Network.HTTP.Types as Http-import qualified Paths_patrol as Package-import qualified Patrol.Type.Dsn as Dsn-import qualified Patrol.Type.Event as Event-import qualified Patrol.Type.EventId as EventId-import qualified Patrol.Type.Response as Response---- | <https://develop.sentry.dev/sdk/store/>-store :: Client.Manager -> Dsn.Dsn -> Event.Event -> IO EventId.EventId-store manager dsn event = do- now <- Time.getCurrentTime- request <- Client.parseUrlThrow $ makeUrl dsn- -- TODO: Compress request body.- response <- Client.httpLbs request- { Client.requestBody = Client.RequestBodyLBS $ Aeson.encode event- , Client.requestHeaders =- [ (Http.hContentType, utf8 "application/json")- , (Http.hUserAgent, utf8 userAgent)- , (ci $ utf8 "X-Sentry-Auth", Text.encodeUtf8 . Text.intercalate (Text.singleton ',') $ Maybe.catMaybes- [ Just $ Text.pack "Sentry sentry_version=7"- , Just . Text.pack $ "sentry_client=" <> userAgent- , Just . Text.pack $ "sentry_timestamp=" <> Time.formatTime Time.defaultTimeLocale "%s" now- , Just $ Text.pack "sentry_key=" <> Dsn.publicKey dsn- , (\ x -> Text.pack "sentry_secret=" <> x) <$> Dsn.secretKey dsn- ])- ]- , Client.method = Http.methodPost- } manager- -- TODO: Handle 429 response codes.- either fail (pure . Response.id_) . Aeson.eitherDecode $ Client.responseBody response--makeUrl :: Dsn.Dsn -> String-makeUrl dsn =- Text.unpack (Dsn.protocol dsn)- <> "://"- <> Text.unpack (Dsn.host dsn)- <> maybe "" (\ x -> ":" <> Text.unpack x) (Dsn.port dsn)- <> Text.unpack (Dsn.path dsn)- <> "api/"- <> Text.unpack (Dsn.projectId dsn)- <> "/store/"--utf8 :: String -> ByteString.ByteString-utf8 = Text.encodeUtf8 . Text.pack--ci :: CI.FoldCase a => a -> CI.CI a-ci = CI.mk--userAgent :: String-userAgent = "patrol/" <> Version.showVersion Package.version
− src/lib/Patrol/Type/Dsn.hs
@@ -1,75 +0,0 @@-module Patrol.Type.Dsn- ( Dsn(..)- , fromUri- , fromString- , toUri- , toString- ) where--import qualified Data.Text as Text-import qualified Network.URI as Uri-import qualified Patrol.Utility.Maybe as Maybe---- | <https://develop.sentry.dev/sdk/overview/#parsing-the-dsn>-data Dsn = Dsn- { protocol :: Text.Text- , publicKey :: Text.Text- , secretKey :: Maybe Text.Text- , host :: Text.Text- , port :: Maybe Text.Text- , path :: Text.Text- , projectId :: Text.Text- } deriving (Eq, Show)--fromUri :: Uri.URI -> Either String Dsn-fromUri uri = do- protocol <- Maybe.note "invalid protocol"- . Text.stripSuffix (Text.singleton ':')- . Text.pack- $ Uri.uriScheme uri- authority <- Maybe.note "missing authority" $ Uri.uriAuthority uri- userInfo <- Maybe.note "invalid user info"- . Text.stripSuffix (Text.singleton '@')- . Text.pack- $ Uri.uriUserInfo authority- let- (publicKey, secretKey) = Text.drop 1- <$> Text.breakOn (Text.singleton ':') userInfo- (host, port) = fmap (Text.drop 1) . Text.breakOn (Text.singleton ':')- . Text.pack- $ Uri.uriRegName authority <> Uri.uriPort authority- (path, projectId) = Text.breakOnEnd (Text.singleton '/')- . Text.pack- $ Uri.uriPath uri- Right Dsn- { protocol- , publicKey- , secretKey = if Text.null secretKey then Nothing else Just secretKey- , host- , port = if Text.null port then Nothing else Just port- , path- , projectId- }--fromString :: String -> Either String Dsn-fromString string = do- uri <- Maybe.note "invalid URI" $ Uri.parseURI string- fromUri uri--toUri :: Dsn -> Uri.URI-toUri dsn = Uri.URI- { Uri.uriScheme = Text.unpack (protocol dsn) <> ":"- , Uri.uriAuthority = Just Uri.URIAuth- { Uri.uriUserInfo = Text.unpack (publicKey dsn)- <> maybe "" (\ x -> ":" <> Text.unpack x) (secretKey dsn) <> "@"- , Uri.uriRegName = Text.unpack (host dsn)- <> maybe "" (\ x -> ":" <> Text.unpack x) (port dsn)- , Uri.uriPort = ""- }- , Uri.uriPath = Text.unpack (path dsn) <> Text.unpack (projectId dsn)- , Uri.uriQuery = ""- , Uri.uriFragment = ""- }--toString :: Dsn -> String-toString dsn = Uri.uriToString id (toUri dsn) ""
− src/lib/Patrol/Type/Event.hs
@@ -1,86 +0,0 @@-module Patrol.Type.Event- ( Event(..)- , new- ) where--import qualified Control.Monad.IO.Class as IO-import qualified Data.Aeson as Aeson-import qualified Data.Map as Map-import qualified Data.Maybe as Maybe-import qualified Data.Text as Text-import qualified Data.Time as Time-import qualified Data.UUID.V4 as Uuid-import qualified Patrol.Type.EventId as EventId-import qualified Patrol.Type.Exception as Exception-import qualified Patrol.Type.Level as Level-import qualified Patrol.Type.Platform as Platform-import qualified Patrol.Type.Request as Request-import qualified Patrol.Type.Timestamp as Timestamp-import qualified Patrol.Type.User as User-import qualified Patrol.Utility.Json as Json---- | <https://develop.sentry.dev/sdk/event-payloads/>-data Event = Event- { dist :: Maybe Text.Text- , environment :: Maybe Text.Text- , eventId :: EventId.EventId- , exception :: Maybe [Exception.Exception]- , extra :: Maybe Aeson.Object- , fingerprint :: Maybe [Text.Text]- , level :: Maybe Level.Level- , logger :: Maybe Text.Text- , modules :: Maybe (Map.Map Text.Text Text.Text)- , platform :: Platform.Platform- , release :: Maybe Text.Text- , request :: Maybe Request.Request- , serverName :: Maybe Text.Text- , tags :: Maybe (Map.Map Text.Text Text.Text)- , timestamp :: Timestamp.Timestamp- , transaction :: Maybe Text.Text- , user :: Maybe User.User- } deriving (Eq, Show)--instance Aeson.ToJSON Event where- toJSON event = Aeson.object $ Maybe.catMaybes- [ Json.pair "dist" <$> dist event- , Json.pair "environment" <$> environment event- , Just . Json.pair "event_id" $ eventId event- , Json.pair "extra" <$> extra event- , Json.pair "exception" . Aeson.object . pure . Json.pair "values" <$> exception event- , Json.pair "fingerprint" <$> fingerprint event- , Json.pair "level" <$> level event- , Json.pair "logger" <$> logger event- , Json.pair "modules" <$> modules event- , Just . Json.pair "platform" $ platform event- , Json.pair "release" <$> release event- , Json.pair "request" <$> request event- , Json.pair "server_name" <$> serverName event- , Json.pair "tags" <$> tags event- , Just . Json.pair "timestamp" $ timestamp event- , Json.pair "transaction" <$> transaction event- , Json.pair "user" <$> user event- ]--new :: IO.MonadIO io => io Event-new = IO.liftIO $ do- eventId <- EventId.fromUuid <$> Uuid.nextRandom- timestamp <- Timestamp.fromUtcTime <$> Time.getCurrentTime- pure Event- { dist = Nothing- , environment = Nothing- , eventId- , exception = Nothing- , extra = Nothing- , fingerprint = Nothing- , level = Nothing- , logger = Nothing- , modules = Nothing- , platform = Platform.Haskell- , release = Nothing- , request = Nothing- , serverName = Nothing- , tags = Nothing- , timestamp- , transaction = Nothing- , user = Nothing- }
− src/lib/Patrol/Type/EventId.hs
@@ -1,30 +0,0 @@-module Patrol.Type.EventId- ( EventId- , fromUuid- , toUuid- ) where--import qualified Data.Aeson as Aeson-import qualified Data.Text as Text-import qualified Data.UUID as Uuid---- | <https://develop.sentry.dev/sdk/event-payloads/#required-attributes>-newtype EventId- = EventId Uuid.UUID- deriving (Eq, Show)--instance Aeson.FromJSON EventId where- parseJSON = Aeson.withText "EventId" $ \ text -> case Text.chunksOf 4 text of- [a, b, c, d, e, f, g, h] -> maybe (fail "invalid EventId") (pure . fromUuid)- . Uuid.fromText- $ Text.intercalate (Text.singleton '-') [a <> b, c, d, e, f <> g <> h]- _ -> fail "invalid EventId"--instance Aeson.ToJSON EventId where- toJSON = Aeson.toJSON . Text.filter (/= '-') . Uuid.toText . toUuid--fromUuid :: Uuid.UUID -> EventId-fromUuid = EventId--toUuid :: EventId -> Uuid.UUID-toUuid (EventId x) = x
− src/lib/Patrol/Type/Exception.hs
@@ -1,38 +0,0 @@-module Patrol.Type.Exception- ( Exception(..)- , fromSomeException- ) where--import qualified Control.Exception as Exception-import qualified Data.Aeson as Aeson-import qualified Data.Maybe as Maybe-import qualified Data.Text as Text-import qualified Data.Typeable as Typeable-import qualified Patrol.Type.StackTrace as StackTrace-import qualified Patrol.Utility.Json as Json---- | <https://develop.sentry.dev/sdk/event-payloads/exception/>-data Exception = Exception- { module_ :: Maybe Text.Text- , stackTrace :: Maybe StackTrace.StackTrace- , type_ :: Text.Text- , value :: Text.Text- } deriving (Eq, Show)--instance Aeson.ToJSON Exception where- toJSON exception = Aeson.object $ Maybe.catMaybes- [ Json.pair "module" <$> module_ exception- , Json.pair "stacktrace" <$> stackTrace exception- , Just . Json.pair "type" $ type_ exception- , Just . Json.pair "value" $ value exception- ]--fromSomeException :: Exception.SomeException -> Exception-fromSomeException (Exception.SomeException x) =- let tyCon = Typeable.typeRepTyCon $ Typeable.typeOf x- in Exception- { module_ = Just . Text.pack $ Typeable.tyConPackage tyCon <> ":" <> Typeable.tyConModule tyCon- , stackTrace = Nothing- , type_ = Text.pack $ Typeable.tyConName tyCon- , value = Text.pack $ Exception.displayException x- }
− src/lib/Patrol/Type/Frame.hs
@@ -1,40 +0,0 @@-module Patrol.Type.Frame- ( Frame(..)- , fromSrcLoc- ) where--import qualified Data.Aeson as Aeson-import qualified Data.Maybe as Maybe-import qualified Data.Text as Text-import qualified GHC.Stack as Stack-import qualified Patrol.Utility.Json as Json---- | <https://develop.sentry.dev/sdk/event-payloads/stacktrace/#frame-attributes>-data Frame = Frame- { colno :: Maybe Int- , filename :: Maybe Text.Text- , function :: Text.Text- , lineno :: Maybe Int- , module_ :: Maybe Text.Text- , package :: Maybe Text.Text- } deriving (Eq, Show)--instance Aeson.ToJSON Frame where- toJSON frame = Aeson.object $ Maybe.catMaybes- [ Json.pair "colno" <$> colno frame- , Json.pair "filename" <$> filename frame- , Just . Json.pair "function" $ function frame- , Json.pair "lineno" <$> lineno frame- , Json.pair "module" <$> module_ frame- , Json.pair "package" <$> package frame- ]--fromSrcLoc :: String -> Stack.SrcLoc -> Frame-fromSrcLoc function srcLoc = Frame- { colno = Just $ Stack.srcLocStartCol srcLoc- , filename = Just . Text.pack $ Stack.srcLocFile srcLoc- , function = Text.pack function- , lineno = Just $ Stack.srcLocStartLine srcLoc- , module_ = Just . Text.pack $ Stack.srcLocModule srcLoc- , package = Just . Text.pack $ Stack.srcLocPackage srcLoc- }
− src/lib/Patrol/Type/Level.hs
@@ -1,22 +0,0 @@-module Patrol.Type.Level- ( Level(..)- ) where--import qualified Data.Aeson as Aeson---- | <https://develop.sentry.dev/sdk/event-payloads/#optional-attributes>-data Level- = Fatal- | Error- | Warning- | Info- | Debug- deriving (Eq, Show)--instance Aeson.ToJSON Level where- toJSON level = Aeson.toJSON $ case level of- Fatal -> "fatal"- Error -> "error"- Warning -> "warning"- Info -> "info"- Debug -> "debug"
− src/lib/Patrol/Type/Platform.hs
@@ -1,50 +0,0 @@-module Patrol.Type.Platform- ( Platform(..)- ) where--import qualified Data.Aeson as Aeson---- | <https://develop.sentry.dev/sdk/event-payloads/#required-attributes>-data Platform- = As3- | C- | Cfml- | Cocoa- | Csharp- | Elixir- | Go- | Groovy- | Haskell- | Java- | Javascript- | Native- | Node- | Objc- | Other- | Perl- | Php- | Python- | Ruby- deriving (Eq, Show)--instance Aeson.ToJSON Platform where- toJSON platform = Aeson.toJSON $ case platform of- As3 -> "as3"- C -> "c"- Cfml -> "cfml"- Cocoa -> "cocoa"- Csharp -> "csharp"- Elixir -> "elixir"- Go -> "go"- Groovy -> "groovy"- Haskell -> "haskell"- Java -> "java"- Javascript -> "javascript"- Native -> "native"- Node -> "node"- Objc -> "objc"- Other -> "other"- Perl -> "perl"- Php -> "php"- Python -> "python"- Ruby -> "ruby"
− src/lib/Patrol/Type/Request.hs
@@ -1,30 +0,0 @@-module Patrol.Type.Request- ( Request(..)- ) where--import qualified Data.Aeson as Aeson-import qualified Data.Map as Map-import qualified Data.Maybe as Maybe-import qualified Data.Text as Text-import qualified Patrol.Utility.Json as Json--data Request = Request- { cookies :: Maybe (Map.Map Text.Text Text.Text)- , data_ :: Maybe Aeson.Value- , env :: Maybe (Map.Map Text.Text Text.Text)- , headers :: Maybe (Map.Map Text.Text Text.Text)- , method :: Maybe Text.Text- , queryString :: Maybe (Map.Map Text.Text Text.Text)- , url :: Maybe Text.Text- } deriving (Eq, Show)--instance Aeson.ToJSON Request where- toJSON request = Aeson.object $ Maybe.catMaybes- [ Json.pair "cookies" <$> cookies request- , Json.pair "env" <$> env request- , Json.pair "headers" <$> headers request- , Json.pair "data" <$> data_ request- , Json.pair "method" <$> method request- , Json.pair "query_string" <$> queryString request- , Json.pair "url" <$> url request- ]
− src/lib/Patrol/Type/Response.hs
@@ -1,17 +0,0 @@-module Patrol.Type.Response- ( Response(..)- ) where--import qualified Data.Aeson as Aeson-import qualified Patrol.Type.EventId as EventId-import qualified Patrol.Utility.Json as Json---- | <https://develop.sentry.dev/sdk/overview/#reading-the-response>-newtype Response = Response- { id_ :: EventId.EventId- } deriving (Eq, Show)--instance Aeson.FromJSON Response where- parseJSON = Aeson.withObject "Response" $ \ object -> do- id_ <- Json.required object "id"- pure Response { id_ }
− src/lib/Patrol/Type/StackTrace.hs
@@ -1,25 +0,0 @@-module Patrol.Type.StackTrace- ( StackTrace(..)- , fromCallStack- ) where--import qualified Data.Aeson as Aeson-import qualified Data.List.NonEmpty as NonEmpty-import qualified GHC.Stack as Stack-import qualified Patrol.Type.Frame as Frame-import qualified Patrol.Utility.Json as Json---- | <https://develop.sentry.dev/sdk/event-payloads/stacktrace/>-newtype StackTrace = StackTrace- { frames :: NonEmpty.NonEmpty Frame.Frame- } deriving (Eq, Show)--instance Aeson.ToJSON StackTrace where- toJSON stackTrace = Aeson.object- [ Json.pair "frames" $ frames stackTrace- ]--fromCallStack :: Stack.CallStack -> Maybe StackTrace-fromCallStack callStack = do- frames <- NonEmpty.nonEmpty . fmap (uncurry Frame.fromSrcLoc) $ Stack.getCallStack callStack- pure StackTrace { frames }
− src/lib/Patrol/Type/Timestamp.hs
@@ -1,22 +0,0 @@-module Patrol.Type.Timestamp- ( Timestamp- , fromUtcTime- , toUtcTime- ) where--import qualified Data.Aeson as Aeson-import qualified Data.Time as Time---- | <https://develop.sentry.dev/sdk/event-payloads/#required-attributes>-newtype Timestamp- = Timestamp Time.UTCTime- deriving (Eq, Show)--instance Aeson.ToJSON Timestamp where- toJSON = Aeson.toJSON . Time.formatTime Time.defaultTimeLocale "%Y-%m-%dT%H:%M:%SZ" . toUtcTime--fromUtcTime :: Time.UTCTime -> Timestamp-fromUtcTime = Timestamp--toUtcTime :: Timestamp -> Time.UTCTime-toUtcTime (Timestamp x) = x
− src/lib/Patrol/Type/User.hs
@@ -1,23 +0,0 @@-module Patrol.Type.User- ( User(..)- ) where--import qualified Data.Aeson as Aeson-import qualified Data.Maybe as Maybe-import qualified Data.Text as Text-import qualified Patrol.Utility.Json as Json--data User = User- { email :: Maybe Text.Text- , id_ :: Maybe Text.Text- , ipAddress :: Maybe Text.Text- , username :: Maybe Text.Text- } deriving (Eq, Show)--instance Aeson.ToJSON User where- toJSON request = Aeson.object $ Maybe.catMaybes- [ Json.pair "email" <$> email request- , Json.pair "id" <$> id_ request- , Json.pair "ipAddress" <$> ipAddress request- , Json.pair "username" <$> username request- ]
− src/lib/Patrol/Utility/Json.hs
@@ -1,14 +0,0 @@-module Patrol.Utility.Json- ( pair- , required- ) where--import qualified Data.Aeson as Aeson-import qualified Data.Aeson.Types as Aeson-import qualified Data.String as String--pair :: (Aeson.ToJSON value, Aeson.KeyValue pair) => String -> value -> pair-pair key value = String.fromString key Aeson..= value--required :: Aeson.FromJSON value => Aeson.Object -> String -> Aeson.Parser value-required object key = object Aeson..: String.fromString key
− src/lib/Patrol/Utility/Maybe.hs
@@ -1,6 +0,0 @@-module Patrol.Utility.Maybe- ( note- ) where--note :: e -> Maybe a -> Either e a-note e = maybe (Left e) Right