oughta 0.1.1.0 → 0.2.0.0
raw patch · 9 files changed
+87/−18 lines, 9 filesdep ~basedep ~exceptionsdep ~file-embedPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: base, exceptions, file-embed, hslua, oughta, text
API changes (from Hackage documentation)
+ Oughta: Hooks :: Lua () -> Lua () -> Hooks
+ Oughta: [postHook] :: Hooks -> Lua ()
+ Oughta: [preHook] :: Hooks -> Lua ()
+ Oughta: data Hooks
+ Oughta: defaultHooks :: Hooks
- Oughta: check :: LuaProgram -> Output -> IO Result
+ Oughta: check :: Hooks -> LuaProgram -> Output -> IO Result
- Oughta: check' :: HasCallStack => LuaProgram -> Output -> IO ()
+ Oughta: check' :: HasCallStack => Hooks -> LuaProgram -> Output -> IO ()
Files
- CHANGELOG.md +8/−0
- README.md +10/−2
- oughta.cabal +9/−8
- src/Oughta.hs +9/−3
- src/Oughta/Hooks.hs +21/−0
- src/Oughta/LuaApi.hs +20/−3
- test-data/fail/reset.txt +4/−0
- test-data/pass/reset.txt +4/−0
- test/Test.hs +2/−2
CHANGELOG.md view
@@ -1,3 +1,11 @@+# [0.2.0.0] -- 2025-05-02++[0.2.0.0]: https://github.com/GaloisInc/oughta/releases/tag/v0.2.0.0++- Add hooks, `Lua` actions that run before or after Lua programs. To upgrade+ from v0.1, just add `defaultHooks` as the first argument to `check{,'}`.+- Add the `reset` function to the Lua API.+ # [0.1.1.0] -- 2025-04-22 [0.1.1.0]: https://github.com/GaloisInc/oughta/releases/tag/v0.1.1.0
README.md view
@@ -21,8 +21,11 @@ check "world" ``` -Oughta draws inspiration from LLVM's [FileCheck] and Rust's [compiletest].+Oughta draws inspiration from [DejaGNU] (which is used to test [GCC]), LLVM's+[FileCheck], and Rust's [compiletest]. +[DejaGNU]: https://www.gnu.org/software/dejagnu/+[GCC]: https://gcc.gnu.org/ [FileCheck]: https://llvm.org/docs/CommandGuide/FileCheck.html [compiletest]: https://rustc-dev-guide.rust-lang.org/tests/compiletest.html @@ -193,12 +196,14 @@ Checking functions: - `check(s: String)`: Find `s` in `text`. Seek to after the end of `s`. Like- LLVM FileCheck's `CHECK`.+ LLVM FileCheck's `CHECK`, or [Expect's][expect] `expect`. - `checkln(s: String)`: `checkln(s)` is equivalent to `check(s .. "\n")`. - `here(s: String)`: Check that `text` beings with `s`. Seek to after the end of `s`. - `hereln(String)`: `hereln(s)` is equivalent to `here(s .. "\n")`. +[expect]: https://core.tcl-lang.org/expect/index+ Other utilities: - `col() -> Int`: Get the current line number of `text` in the output.@@ -212,6 +217,9 @@ - `fail()`: Fail to match at this point in `text`. - `match(n: Integer)`: Consume `n` bytes of `text`, treating them as a match. - `seek(n: Integer)`: Seek forward `n` bytes in `text`.+- `reset(name: String, s: String)`: Set `text` to `s` and reset the program+ state (e.g., location tracking). Treat `name` as the file name for `s` in+ user-facing output. ## Motivation
oughta.cabal view
@@ -1,6 +1,6 @@-cabal-version: 2.4+cabal-version: 3.0 name: oughta-version: 0.1.1.0+version: 0.2.0.0 author: Galois, Inc. maintainer: grease@galois.com copyright: Galois, Inc. 2025@@ -26,7 +26,7 @@ common shared default-language: GHC2021- build-depends: base >= 4.17 && < 5+ build-depends: base ^>= { 4.17, 4.18, 4.19, 4.20, 4.21 }, -- Specifying -Wall and -Werror can cause the project to fail to build on -- newer versions of GHC simply due to new warnings being added to -Wall. To@@ -135,16 +135,17 @@ build-depends: bytestring, containers,- exceptions >= 0.10 && < 0.11,- file-embed >= 0.0.16 && < 0.1,- hslua >= 2.3 && < 2.4,- text,+ exceptions ^>= 0.10,+ file-embed ^>= 0.0.15,+ hslua ^>= 2.3,+ text ^>= { 2, 2.1 }, exposed-modules: Oughta other-modules: Oughta.Exception Oughta.Extract+ Oughta.Hooks Oughta.Lua Oughta.LuaApi Oughta.Pos@@ -157,7 +158,7 @@ hs-source-dirs: test main-is: Test.hs build-depends:- oughta+ oughta >= 0.2.0.0, build-depends: bytestring, directory,
src/Oughta.hs view
@@ -21,12 +21,16 @@ , Loc(..) , Pos(..) , OP.Span(..)+ -- * Hooks+ , OH.Hooks(..)+ , OH.defaultHooks ) where import Control.Exception qualified as X import Data.ByteString (ByteString) import Oughta.Extract (LuaProgram) import Oughta.Extract qualified as OE+import Oughta.Hooks qualified as OH import Oughta.LuaApi qualified as FCLA import Oughta.Pos (Loc(..), Pos(..)) import Oughta.Pos qualified as OP@@ -39,19 +43,21 @@ -- | Check some program output against a Oughta Lua program. check ::+ OH.Hooks -> LuaProgram -> Output -> IO OR.Result-check prog (Output out) = FCLA.check prog out+check hooks prog (Output out) = FCLA.check hooks prog out -- | Like 'check', but throws an exception on failure. check' :: HasCallStack =>+ OH.Hooks -> LuaProgram -> Output -> IO ()-check' prog out = do- OR.Result r <- check prog out+check' hooks prog out = do+ OR.Result r <- check hooks prog out case r of Left f -> X.throwIO f Right {} -> pure ()
+ src/Oughta/Hooks.hs view
@@ -0,0 +1,21 @@+module Oughta.Hooks+ ( Hooks(..)+ , defaultHooks+ ) where++import HsLua (Lua)++data Hooks+ = Hooks+ { -- | Hook that runs before execution of the Lua program+ preHook :: Lua ()+ -- | Hook that runs after successful execution of the Lua program+ , postHook :: Lua ()+ }++defaultHooks :: Hooks+defaultHooks =+ Hooks+ { preHook = pure ()+ , postHook = pure ()+ }
src/Oughta/LuaApi.hs view
@@ -17,6 +17,7 @@ import Oughta.Exception (Exception) import Oughta.Exception qualified as OE import Oughta.Extract (LuaProgram, SourceMap, lookupSourceMap, programText, sourceMap, sourceMapFile)+import Oughta.Hooks qualified as OH import Oughta.Lua qualified as OL import Oughta.Pos qualified as OP import Oughta.Result (Progress, Result)@@ -85,6 +86,13 @@ } pure (OR.updateProgress m p) +-- | Implementation of @reset@. Not exported.+reset :: IORef Progress -> String -> ByteString -> Lua.LuaE Exception ()+reset stateRef name txt = do+ setText txt+ let p0 = OR.newProgress name txt+ liftIO (IORef.writeIORef stateRef p0)+ -- | Implementation of @seek@. Not exported. seek :: IORef Progress -> Int -> Lua.LuaE Exception () seek stateRef chars =@@ -123,13 +131,14 @@ -- | Load user and Oughta Lua code. Helper, not exported. luaSetup ::+ OH.Hooks -> IORef Progress -> -- | User code LuaProgram -> -- | Initial content of @text@ global ByteString -> Lua.LuaE Exception ()-luaSetup stateRef prog txt = do+luaSetup hooks stateRef prog txt = do Lua.openlibs setText txt @@ -150,6 +159,9 @@ Lua.pushHaskellFunction (Lua.toHaskellFunction (match sm stateRef)) Lua.setglobal (Lua.Name "match") + Lua.pushHaskellFunction (Lua.toHaskellFunction (reset stateRef))+ Lua.setglobal (Lua.Name "reset")+ Lua.pushHaskellFunction (Lua.toHaskellFunction (seek stateRef)) Lua.setglobal (Lua.Name "seek") @@ -159,20 +171,25 @@ _ <- Lua.loadbuffer OL.luaCode (Lua.Name "oughta.lua") Lua.call 0 0 + Lua.changeErrorType (OH.preHook hooks)+ let nm = Lua.Name (Text.encodeUtf8 (sourceMapFile sm)) _ <- Lua.loadbuffer (Text.encodeUtf8 (programText prog)) nm Lua.call 0 0 + Lua.changeErrorType (OH.postHook hooks)+ -- | Check some text against a Lua program using the API. check ::+ OH.Hooks -> LuaProgram -> -- | Text to check ByteString -> IO Result-check prog txt = do+check hooks prog txt = do let p0 = OR.newProgress "<out>" txt stateRef <- IORef.newIORef p0- result <- Lua.run (Lua.try (luaSetup stateRef prog txt))+ result <- Lua.run (Lua.try (luaSetup hooks stateRef prog txt)) case result of Left (OE.LuaException e) -> X.throwIO e Left (OE.Failure noMatch) ->
+ test-data/fail/reset.txt view
@@ -0,0 +1,4 @@+# reset("<out>", "bar")+# check "foo"+foo+; check "❌"
+ test-data/pass/reset.txt view
@@ -0,0 +1,4 @@+# reset("<out>", "bar")+# check "bar"+foo+; match_on_line(1)
test/Test.hs view
@@ -51,14 +51,14 @@ let prog0 = Ota.fromLineComments file comment content let prog = Ota.addPrefix (Text.decodeUtf8Lenient prelude) prog0- result <- Ota.check prog (clearComments content)+ result <- Ota.check Ota.defaultHooks prog (clearComments content) TTH.assertBool file (not (Ota.resultNull result)) let prog0' = Ota.fromLineComments file comment' content let prog' = Ota.addPrefix (Text.decodeUtf8Lenient prelude) prog0' let output'@(Ota.Output out) = clearComments (Ota.printResult result) BS.writeFile (FilePath.replaceExtension file "out") out- Ota.check' prog' output'+ Ota.check' Ota.defaultHooks prog' output' discover :: FilePath -> IO [TT.TestTree] discover dir = do