diff --git a/.github/workflows/haskell-ci.yml b/.github/workflows/haskell-ci.yml index 2e71619..738d201 100644 --- a/.github/workflows/haskell-ci.yml +++ b/.github/workflows/haskell-ci.yml @@ -1,4 +1,6 @@ name: Haskell-CI +permissions: + contents: read on: push: @@ -15,13 +17,13 @@ concurrency: cancel-in-progress: true jobs: - linux: + test-with-cabal: name: Haskell-CI - Linux - ${{ matrix.ghc-version }} strategy: matrix: ghc-version: [latest, 9.12, "9.10", 9.8, 9.6] - os: [ubuntu-24.04] + os: [ubuntu-latest] fail-fast: false runs-on: ${{ matrix.os }} @@ -43,3 +45,45 @@ jobs: with: key: ${{ matrix.os }}-${{ matrix.ghc-version }}-${{ github.sha }} path: ~/.cabal/store + + test-with-stack: + name: Stack + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: haskell-actions/setup@v2 + id: setup-haskell-stack + name: Setup Haskell + with: + enable-stack: true + stack-version: latest + ghc-version: 9.6.7 + + - name: Cache + id: cache + uses: actions/cache@v4 + with: + path: | + ${{ steps.setup-haskell-stack.outputs.stack-root }} + .stack-work + key: ${{ runner.os }}-stack-${{ github.sha }} + restore-keys: ${{ runner.os }}-stack + + - name: Test + run: stack test --coverage --flag constrained-generators:dev + + - uses: actions/cache/save@v4 + with: + path: | + ${{ steps.setup-haskell-stack.outputs.stack-root }} + .stack-work + key: ${{ runner.os }}-stack-${{ github.sha }} + + - name: Upload coverage report + env: + COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} + run: | + [ -n "${COVERALLS_REPO_TOKEN}" ] + curl -L https://github.com/rubik/stack-hpc-coveralls/releases/download/v0.0.7.0/shc-Linux-X64.tar.bz2 | tar xj shc + ./shc --repo-token="$COVERALLS_REPO_TOKEN" --partial-coverage --fetch-coverage combined all diff --git a/constrained-generators.cabal b/constrained-generators.cabal index a60c53b..d3d1f7d 100644 --- a/constrained-generators.cabal +++ b/constrained-generators.cabal @@ -121,7 +121,7 @@ library examples prettyprinter, random, -test-suite constrained +test-suite constrained-tests type: exitcode-stdio-1.0 main-is: Tests.hs hs-source-dirs: test @@ -141,9 +141,12 @@ test-suite constrained QuickCheck, base, constrained-generators, - constrained-generators:examples, containers, - hspec, + hspec + + if !flag(dev) + build-depends: + constrained-generators:examples benchmark bench type: exitcode-stdio-1.0 diff --git a/examples/Constrained/Examples/Basic.hs b/examples/Constrained/Examples/Basic.hs index bbda1ae..fda7fbe 100644 --- a/examples/Constrained/Examples/Basic.hs +++ b/examples/Constrained/Examples/Basic.hs @@ -363,3 +363,6 @@ pairCant = constrained' $ \ [var| i |] [var| p |] -> , not_ $ k `elem_` lit [1..9] ] ] + +signumPositive :: Specification Rational +signumPositive = constrained $ \ x -> signum (x * 30) >=. 1 diff --git a/src/Constrained/NumOrd.hs b/src/Constrained/NumOrd.hs index df4027a..021f809 100644 --- a/src/Constrained/NumOrd.hs +++ b/src/Constrained/NumOrd.hs @@ -774,6 +774,33 @@ instance {-# OVERLAPPABLE #-} (HasSpec a, MaybeBounded a, Integral a, TypeSpec a then r - signum a else r +instance HasDivision (Ratio Integer) where + doDivide = (/) + + divideSpec 0 _ = TrueSpec + divideSpec a (NumSpecInterval ml mu) = typeSpec ts + where + ts | a > 0 = NumSpecInterval ml' mu' + | otherwise = NumSpecInterval mu' ml' + ml' = adjustLowerBound <$> ml + mu' = adjustUpperBound <$> mu + adjustLowerBound l = + let r = l / a + l' = r * a + in + if l' < l + then r + (l - l') * 2 / a + else r + + adjustUpperBound u = + let r = u / a + u' = r * a + in + if u < u' + then r - (u' - u) * 2 / a + else r + + instance HasDivision Float where doDivide = (/) diff --git a/stack.yaml b/stack.yaml new file mode 100644 index 0000000..01c0455 --- /dev/null +++ b/stack.yaml @@ -0,0 +1,4 @@ +snapshot: lts-22.44 +packages: +- . +system-ghc: true diff --git a/stack.yaml.lock b/stack.yaml.lock new file mode 100644 index 0000000..8d134eb --- /dev/null +++ b/stack.yaml.lock @@ -0,0 +1,12 @@ +# This file was autogenerated by Stack. +# You should not edit this file by hand. +# For more information, please see the documentation at: +# https://docs.haskellstack.org/en/stable/topics/lock_files + +packages: [] +snapshots: +- completed: + sha256: 238fa745b64f91184f9aa518fe04bdde6552533d169b0da5256670df83a0f1a9 + size: 721141 + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/22/44.yaml + original: lts-22.44 diff --git a/test/Constrained/Tests.hs b/test/Constrained/Tests.hs index 685c035..52f9217 100644 --- a/test/Constrained/Tests.hs +++ b/test/Constrained/Tests.hs @@ -1,4 +1,5 @@ {-# LANGUAGE AllowAmbiguousTypes #-} +{-# LANGUAGE CPP #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} @@ -59,6 +60,10 @@ testAll = hspec $ tests False tests :: Bool -> Spec tests nightly = describe "constrained" . modifyMaxSuccess (\ms -> if nightly then ms * 10 else ms) $ do + testSpec "signumPositive" signumPositive + testSpec "setOfPairLetSpec" setOfPairLetSpec + testSpec "setPair" setPair + testSpec "mapElemSpec" mapElemSpec testSpec "complicatedEither" complicatedEither testSpec "pairCant" pairCant -- TODO: figure out why this doesn't shrink @@ -70,7 +75,6 @@ tests nightly = testSpec "assertRealMultiple" assertRealMultiple testSpec "setSpec" setSpec testSpec "leqPair" leqPair - testSpec "setPair" setPair testSpecNoShrink "listEmpty" listEmpty testSpec "compositionalSpec" compositionalSpec testSpec "simplePairSpec" simplePairSpec @@ -80,7 +84,6 @@ tests nightly = testSpec "maybeSpec" maybeSpec testSpecNoShrink "eitherSetSpec" eitherSetSpec testSpec "fooSpec" fooSpec - testSpec "mapElemSpec" mapElemSpec testSpec "mapElemKeySpec" mapElemKeySpec -- TODO: figure out why this doesn't shrink testSpecNoShrink "mapIsJust" mapIsJust @@ -95,7 +98,6 @@ tests nightly = -- more detailed shrinking of `SuspendedSpec`s testSpecNoShrink "setPairSpec" setPairSpec testSpec "fixedSetSpec" fixedSetSpec - testSpec "setOfPairLetSpec" setOfPairLetSpec testSpecNoShrink "emptyEitherSpec" emptyEitherSpec testSpecNoShrink "emptyEitherMemberSpec" emptyEitherMemberSpec testSpec "setSingletonSpec" setSingletonSpec @@ -316,11 +318,13 @@ testSpec' withShrink n s = do checkCoverage' $ prop_constrained_explained s +#if MIN_VERSION_QuickCheck(2, 15, 0) when withShrink $ prop "prop_shrink_sound" $ discardAfter 100_000 $ checkCoverage' $ prop_shrink_sound s +#endif ------------------------------------------------------------------------ -- Test properties of the instance Num (NumSpec Integer)