Compare commits

..

No commits in common. "master" and "v0.0.4" have entirely different histories.

17 changed files with 303 additions and 537 deletions

View File

@ -1,158 +1,95 @@
# This Travis job script has been generated by a script via
#
# haskell-ci '--config=cabal.haskell-ci' 'servant-quickcheck.cabal'
# make_travis_yml_2.hs '--branch' 'master' '-o' '.travis.yml' 'servant-quickcheck.cabal'
#
# To regenerate the script (for example after adjusting tested-with) run
# For more information, see https://github.com/hvr/multi-ghc-travis
#
# haskell-ci regenerate
#
# For more information, see https://github.com/haskell-CI/haskell-ci
#
# version: 0.10.1
#
version: ~> 1.0
language: c
os: linux
dist: xenial
sudo: false
git:
# whether to recursively clone submodules
submodules: false
submodules: false # whether to recursively clone submodules
branches:
only:
- master
cache:
directories:
- $HOME/.cabal/packages
- $HOME/.cabal/store
- $HOME/.hlint
before_cache:
- rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log
# remove files that are regenerated by 'cabal update'
- rm -fv $CABALHOME/packages/hackage.haskell.org/00-index.*
- rm -fv $CABALHOME/packages/hackage.haskell.org/*.json
- rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.cache
- rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar
- rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar.idx
- rm -rfv $CABALHOME/packages/head.hackage
jobs:
include:
- compiler: ghc-8.8.3
addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.8.3","cabal-install-3.2"]}}
os: linux
- compiler: ghc-8.6.5
addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.5","cabal-install-3.2"]}}
os: linux
- compiler: ghc-8.4.4
addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.4.4","cabal-install-3.2"]}}
os: linux
- compiler: ghc-8.2.2
addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.2.2","cabal-install-3.2"]}}
os: linux
- compiler: ghc-8.0.2
addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.0.2","cabal-install-3.2"]}}
os: linux
before_install:
- HC=$(echo "/opt/$CC/bin/ghc" | sed 's/-/\//')
- WITHCOMPILER="-w $HC"
- HADDOCK=$(echo "/opt/$CC/bin/haddock" | sed 's/-/\//')
- HCPKG="$HC-pkg"
- unset CC
- CABAL=/opt/ghc/bin/cabal
- CABALHOME=$HOME/.cabal
- export PATH="$CABALHOME/bin:$PATH"
- TOP=$(pwd)
- "HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\\d+)\\.(\\d+)\\.(\\d+)(\\.(\\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')"
- echo $HCNUMVER
- CABAL="$CABAL -vnormal+nowrap"
- set -o pipefail
- TEST=--enable-tests
- BENCH=--enable-benchmarks
- HEADHACKAGE=false
- rm -f $CABALHOME/config
- |
echo "verbose: normal +nowrap +markoutput" >> $CABALHOME/config
echo "remote-build-reporting: anonymous" >> $CABALHOME/config
echo "write-ghc-environment-files: always" >> $CABALHOME/config
echo "remote-repo-cache: $CABALHOME/packages" >> $CABALHOME/config
echo "logs-dir: $CABALHOME/logs" >> $CABALHOME/config
echo "world-file: $CABALHOME/world" >> $CABALHOME/config
echo "extra-prog-path: $CABALHOME/bin" >> $CABALHOME/config
echo "symlink-bindir: $CABALHOME/bin" >> $CABALHOME/config
echo "installdir: $CABALHOME/bin" >> $CABALHOME/config
echo "build-summary: $CABALHOME/logs/build.log" >> $CABALHOME/config
echo "store-dir: $CABALHOME/store" >> $CABALHOME/config
echo "install-dirs user" >> $CABALHOME/config
echo " prefix: $CABALHOME" >> $CABALHOME/config
echo "repository hackage.haskell.org" >> $CABALHOME/config
echo " url: http://hackage.haskell.org/" >> $CABALHOME/config
install:
- ${CABAL} --version
- echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"
- |
echo "program-default-options" >> $CABALHOME/config
echo " ghc-options: $GHCJOBS +RTS -M6G -RTS" >> $CABALHOME/config
- cat $CABALHOME/config
- rm -fv cabal.project cabal.project.local cabal.project.freeze
- travis_retry ${CABAL} v2-update -v
# Generate cabal.project
- rm -rf cabal.project cabal.project.local cabal.project.freeze
- touch cabal.project
- |
echo "packages: ." >> cabal.project
- if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant-quickcheck' >> cabal.project ; fi
- "if [ $HCNUMVER -ge 80200 ] ; then echo ' ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
- |
- "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(servant-quickcheck)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
- cat cabal.project || true
- cat cabal.project.local || true
- if [ -f "./configure.ac" ]; then (cd "." && autoreconf -i); fi
- ${CABAL} v2-freeze $WITHCOMPILER ${TEST} ${BENCH}
- "cat cabal.project.freeze | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'"
- rm cabal.project.freeze
- travis_wait 40 ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} --dep -j2 all
- travis_wait 40 ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --dep -j2 all
script:
- DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)
# Packaging...
- ${CABAL} v2-sdist all
# Unpacking...
- mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/
- cd ${DISTDIR} || false
- find . -maxdepth 1 -type f -name '*.tar.gz' -exec tar -xvf '{}' \;
- find . -maxdepth 1 -type f -name '*.tar.gz' -exec rm '{}' \;
- PKGDIR_servant_quickcheck="$(find . -maxdepth 1 -type d -regex '.*/servant-quickcheck-[0-9.]*')"
# Generate cabal.project
- rm -rf cabal.project cabal.project.local cabal.project.freeze
- touch cabal.project
- |
echo "packages: ${PKGDIR_servant_quickcheck}" >> cabal.project
- if [ $HCNUMVER -ge 80200 ] ; then echo 'package servant-quickcheck' >> cabal.project ; fi
- "if [ $HCNUMVER -ge 80200 ] ; then echo ' ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
- |
- "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(servant-quickcheck)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
- cat cabal.project || true
- cat cabal.project.local || true
# Building...
# this builds all libraries and executables (without tests/benchmarks)
- ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all
# Building with tests and benchmarks...
# build & run tests, build benchmarks
- ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} all
# Testing...
- ${CABAL} v2-test $WITHCOMPILER ${TEST} ${BENCH} all
# cabal check...
- (cd ${PKGDIR_servant_quickcheck} && ${CABAL} -vnormal check)
# haddock...
- ${CABAL} v2-haddock $WITHCOMPILER --with-haddock $HADDOCK ${TEST} ${BENCH} all
# Building without installed constraints for packages in global-db...
- rm -f cabal.project.local
- ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all
# Constraint sets
- rm -rf cabal.project.local
# Constraint set base-compat-0.10
- ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --constraint='base-compat ==0.10.*' all
# Constraint set base-compat-0.11
- ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --constraint='base-compat ==0.11.*' all
# REGENDATA ("0.10.1",["--config=cabal.haskell-ci","servant-quickcheck.cabal"])
before_cache:
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log
# remove files that are regenerated by 'cabal update'
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.*
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/*.json
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.cache
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar.idx
matrix:
include:
- compiler: "ghc-7.10.3"
# env: TEST=--disable-tests BENCH=--disable-benchmarks
addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-7.10.3], sources: [hvr-ghc]}}
- compiler: "ghc-8.0.2"
# env: TEST=--disable-tests BENCH=--disable-benchmarks
addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.0.2], sources: [hvr-ghc]}}
- compiler: "ghc-8.2.1"
# env: TEST=--disable-tests BENCH=--disable-benchmarks
addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.2.1], sources: [hvr-ghc]}}
before_install:
- HC=${CC}
- HCPKG=${HC/ghc/ghc-pkg}
- unset CC
- PATH=/opt/ghc/bin:/opt/ghc-ppa-tools/bin:$PATH
install:
- cabal --version
- echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"
- BENCH=${BENCH---enable-benchmarks}
- TEST=${TEST---enable-tests}
- HADDOCK=${HADDOCK-true}
- INSTALLED=${INSTALLED-true}
- travis_retry cabal update -v
- sed -i.bak 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config
- rm -fv cabal.project.local
- "echo 'packages: .' > cabal.project"
- if [ -f "./configure.ac" ]; then
(cd "."; autoreconf -i);
fi
- rm -f cabal.project.freeze
- cabal new-build -w ${HC} ${TEST} ${BENCH} --project-file="cabal.project" --dep -j2 all
- cabal new-build -w ${HC} --disable-tests --disable-benchmarks --project-file="cabal.project" --dep -j2 all
- rm -rf "."/.ghc.environment.* "."/dist
- DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)
# Here starts the actual work to be performed for the package under test;
# any command which exits with a non-zero exit code causes the build to fail.
script:
# test that source-distributions can be generated
- (cd "."; cabal sdist)
- mv "."/dist/servant-quickcheck-*.tar.gz ${DISTDIR}/
- cd ${DISTDIR}
- find . -maxdepth 1 -name '*.tar.gz' -exec tar -xvf '{}' \;
- "printf 'packages: servant-quickcheck-*/*.cabal\n' > cabal.project"
# this builds all libraries and executables (without tests/benchmarks)
- cabal new-build -w ${HC} --disable-tests --disable-benchmarks all
# Build with installed constraints for packages in global-db
- if $INSTALLED; then
echo cabal new-build -w ${HC} --disable-tests --disable-benchmarks $(${HCPKG} list --global --simple-output --names-only | sed 's/\([a-zA-Z0-9-]\{1,\}\) */--constraint="\1 installed" /g') all | sh;
else echo "Not building with installed constraints"; fi
# build & run tests, build benchmarks
- cabal new-build -w ${HC} ${TEST} ${BENCH} all
- if [ "x$TEST" = "x--enable-tests" ]; then cabal new-test -w ${HC} ${TEST} all; fi
# haddock
- rm -rf ./dist-newstyle
- if $HADDOCK; then cabal new-haddock -w ${HC} --disable-tests --disable-benchmarks all; else echo "Skipping haddock generation";fi
# REGENDATA ["--branch","master","-o",".travis.yml","servant-quickcheck.cabal"]
# EOF

View File

@ -1,98 +1,6 @@
upcoming:
releases:
- version: "0.0.9.0"
changes:
- description: "Support servant-0.15 (#65)"
authors: fizruk
date: 2020-06-25
- description: "Relax constraints for GHC 8.10 (#70)"
authors: felixmulder
date: 2020-06-20
- version: "0.0.8.0"
changes:
- description: Support for servant-0.17
authors: phadej
date: 2019-01-23
- version: "0.0.7.3"
changes:
- description: Support for servant-0.14
issue: 53
authors: phadej
date: 2018-06-12
- description: Fix a failure from OnlyJsonObjects when there is no content-type.
issue: 55
authors: Phenitei
date: 2018-08-27
- description: A bug fix where notAllowedContainsAllowHeader would print the initial request alongside the failure instead of the request causing the failure when it failed.
issue: 57
authors: Phenitei
date: 2018-08-29
- description: QuickCheck 2.12 compatibility
issue: 58
authors: parsonsmatt
date: 2018-10-12
- description: GHC 8.6 compatibility
issue: 59
authors: phadej
date: 2018-10-15
- version: "0.0.7.2"
changes:
- description: Allow client to pass an HTTP Manager in to functions
issue: 47
authors: parsonsmatt
date: 2018-05-10
- description: Fix "should not happen" error when exceptions are thrown
issue: 48
authors: parsonsmatt
date: 2018-05-10
- version: "0.0.7.0"
changes:
- description: Support for base-compat-0.10
issue: none
authors: phadej
date: 2018-04-12
- version: "0.0.7.0"
changes:
- description: Support for GHC-8.4.1
issue: none
authors: phadej
date: 2018-03-23
- description: Requires hspec-2.5
issue: none
authors: phadej
date: 2018-03-23
- version: "0.0.6.0"
changes:
- description: Support for servant-0.12
issue: none
authors: phadej
date: 2018-02-09
- version: "0.0.5.0"
changes:
- description: Export forgotten predicates
issue: none
pr: 40
authors: Phenitei
date: 2017-12-14
- version: "0.0.4"
changes:
@ -101,12 +9,14 @@ releases:
authors: phadej
date: 2017-11-07
- version: "0.0.3.1"
changes:
- description: Support for Servant 0.11
issue: none
pr: 32
authors: adinapoli-iohk
date: 2017-10-18
notes: Includes 0-weighted instance for EmptyAPI
- version: "0.0.3.0"
changes:

View File

@ -1,7 +0,0 @@
branches: master
constraint-set base-compat-0.10
constraints: base-compat ==0.10.*
constraint-set base-compat-0.11
constraints: base-compat ==0.11.*

View File

@ -1,4 +0,0 @@
packages: .
tests: true
allow-newer: servant-blaze:servant

View File

@ -1,31 +0,0 @@
{-# LANGUAGE OverloadedStrings, DataKinds #-}
module Main (main) where
import Servant
import Servant.QuickCheck
import Test.Hspec
import Data.Text (Text)
import System.Environment (getArgs)
main :: IO ()
main = do
args <- getArgs
case args of
[] -> putStrLn "Not running without arguments. Try --help or --fail-fast."
_ -> hspec spec
-- Change to String to reproduce
-- https://github.com/haskell-servant/servant-quickcheck/issues/41
type API = Get '[PlainText] Text
api :: Proxy API
api = Proxy
server :: Server API
server = return "Sigurð Fáfnirslayer"
spec :: Spec
spec = describe "example server" $
it "mangles UTF-8 in error messages" $
withServantServer api (return server) $ \burl ->
serverSatisfies api burl defaultArgs (getsHaveCacheControlHeader <%> mempty)

View File

@ -1,22 +1,26 @@
name: servant-quickcheck
version: 0.0.9.1
synopsis: QuickCheck entire APIs
name: servant-quickcheck
version: 0.0.4
synopsis: QuickCheck entire APIs
description:
This packages provides QuickCheck properties that are tested across an entire
API.
This packages provides QuickCheck properties that are tested across an entire
API.
license: BSD3
license-file: LICENSE
author: Julian K. Arni
maintainer: jkarni@gmail.com
category: Web
build-type: Simple
cabal-version: >=1.10
extra-source-files: CHANGELOG.yaml
tested-with: GHC ==8.0.2 || ==8.2.2 || ==8.4.4 || ==8.6.5 || == 8.8.3
license: BSD3
license-file: LICENSE
author: Julian K. Arni
maintainer: jkarni@gmail.com
category: Web
build-type: Simple
cabal-version: >=1.10
extra-source-files:
CHANGELOG.yaml
tested-with:
GHC==7.10.3,
GHC==8.0.2,
GHC==8.2.1
source-repository head
type: git
type: git
location: https://github.com/haskell-servant/servant-quickcheck
flag long-tests
@ -24,115 +28,89 @@ flag long-tests
default: False
library
exposed-modules:
Servant.QuickCheck
Servant.QuickCheck.Internal
Servant.QuickCheck.Internal.Equality
Servant.QuickCheck.Internal.ErrorTypes
Servant.QuickCheck.Internal.HasGenRequest
Servant.QuickCheck.Internal.Predicates
Servant.QuickCheck.Internal.QuickCheck
exposed-modules: Servant.QuickCheck
, Servant.QuickCheck.Internal
, Servant.QuickCheck.Internal.Predicates
, Servant.QuickCheck.Internal.HasGenRequest
, Servant.QuickCheck.Internal.QuickCheck
, Servant.QuickCheck.Internal.Equality
, Servant.QuickCheck.Internal.ErrorTypes
build-depends: base >=4.8 && <4.11
, base-compat == 0.9.*
, aeson > 0.8 && < 2
, bytestring == 0.10.*
, case-insensitive == 1.2.*
, clock >= 0.7 && < 0.8
, data-default-class >= 0.0 && < 0.2
, hspec >= 2.2 && < 2.5
, http-client >= 0.4.30 && < 0.6
, http-media >= 0.6 && <0.8
, http-types > 0.8 && < 0.11
, mtl > 2.1 && < 2.3
, pretty == 1.1.*
, process >= 1.2 && < 1.7
, QuickCheck > 2.7 && < 2.11
, servant > 0.6 && < 0.13
, servant-client > 0.6 && < 0.13
, servant-server > 0.6 && < 0.13
, split == 0.2.*
, string-conversions > 0.3 && < 0.5
, temporary == 1.2.*
, text == 1.*
, time >= 1.5 && < 1.9
, warp >= 3.2.4 && < 3.3
build-depends:
aeson >=0.8 && <2
, base >=4.9 && <4.15
, base-compat-batteries >=0.10.1 && <0.12
, bytestring >=0.10 && <0.11
, case-insensitive >=1.2 && <1.3
, clock >=0.7 && <0.9
, data-default-class >=0.0 && <0.2
, hspec >=2.5.6 && <2.8
, http-client >=0.4.30 && <0.8
, http-media >=0.6 && <0.9
, http-types >=0.8 && <0.13
, mtl >=2.1 && <2.3
, pretty >=1.1 && <1.2
, process >=1.2 && <1.7
, QuickCheck >=2.7 && <2.15
, servant >=0.17 && <0.19
, servant-client >=0.17 && <0.19
, servant-server >=0.17 && <0.19
, split >=0.2 && <0.3
, string-conversions >=0.3 && <0.5
, temporary >=1.2 && <1.4
, text >=1 && <2
, time >=1.5 && <1.11
, warp >=3.2.4 && <3.4
if !impl(ghc >=8.0)
build-depends: semigroups >=0.18.3 && <0.20
hs-source-dirs: src
default-extensions:
NoImplicitPrelude
ConstraintKinds
DataKinds
DeriveDataTypeable
DeriveFunctor
DeriveGeneric
FlexibleContexts
FlexibleInstances
FunctionalDependencies
GADTs
KindSignatures
MultiParamTypeClasses
OverloadedStrings
RankNTypes
ScopedTypeVariables
TypeOperators
default-language: Haskell2010
hs-source-dirs: src
default-extensions: TypeOperators
, FlexibleInstances
, FlexibleContexts
, DataKinds
, GADTs
, MultiParamTypeClasses
, DeriveFunctor
, KindSignatures
, RankNTypes
, ConstraintKinds
, DeriveGeneric
, ScopedTypeVariables
, OverloadedStrings
, FunctionalDependencies
, NoImplicitPrelude
, DeriveDataTypeable
default-language: Haskell2010
test-suite spec
type: exitcode-stdio-1.0
ghc-options: -Wall -threaded
default-language: Haskell2010
hs-source-dirs: test
main-is: Spec.hs
other-modules: Servant.QuickCheck.InternalSpec
build-tool-depends: hspec-discover:hspec-discover -any
build-depends:
aeson
, base
, base-compat-batteries
, blaze-html
, bytestring
, hspec
, hspec-core >=2.5.5 && <2.8
, http-client
, QuickCheck
, quickcheck-io
, servant
, servant-blaze
, servant-client
, servant-quickcheck
, servant-server
, transformers
, warp
default-extensions:
NoImplicitPrelude
DataKinds
FlexibleContexts
FlexibleInstances
GADTs
OverloadedStrings
ScopedTypeVariables
TypeOperators
type: exitcode-stdio-1.0
ghc-options: -Wall -threaded
default-language: Haskell2010
hs-source-dirs: test
main-is: Spec.hs
other-modules: Servant.QuickCheck.InternalSpec
build-tool-depends: hspec-discover:hspec-discover
build-depends: base == 4.*
, base-compat
, aeson
, servant-quickcheck
, bytestring
, hspec
, hspec-core
, http-client
, blaze-html
, warp
, servant-server
, servant-client
, servant
, servant-blaze
, transformers
, QuickCheck
, quickcheck-io
default-extensions: TypeOperators
, FlexibleInstances
, FlexibleContexts
, GADTs
, DataKinds
, NoImplicitPrelude
, OverloadedStrings
, ScopedTypeVariables
if flag(long-tests)
cpp-options: -DLONG_TESTS
test-suite example
type: exitcode-stdio-1.0
main-is: Main.hs
hs-source-dirs: example
ghc-options: -Wall
build-depends:
base
, hspec
, servant-quickcheck
, servant-server
, text
default-language: Haskell2010
cpp-options: -DLONG_TESTS

View File

@ -29,10 +29,8 @@ module Servant.QuickCheck
, not500
, notLongerThan
, onlyJsonObjects
, honoursAcceptHeader
, notAllowedContainsAllowHeader
, unauthorizedContainsWWWAuthenticate
, getsHaveLastModifiedHeader
, getsHaveCacheControlHeader
, headsHaveCacheControlHeader
, createContainsValidLocation

View File

@ -5,19 +5,15 @@ import Data.ByteString (ByteString)
import qualified Data.ByteString.Lazy as LB
import Data.Function (on)
import Network.HTTP.Client (Response, responseBody)
import Data.Semigroup (Semigroup (..))
import Prelude.Compat
newtype ResponseEquality b
= ResponseEquality { getResponseEquality :: Response b -> Response b -> Bool }
instance Semigroup (ResponseEquality b) where
ResponseEquality a <> ResponseEquality b = ResponseEquality $ \x y ->
a x y && b x y
instance Monoid (ResponseEquality b) where
mempty = ResponseEquality $ \_ _ -> True
mappend = (<>)
ResponseEquality a `mappend` ResponseEquality b = ResponseEquality $ \x y ->
a x y && b x y
-- | Use `Eq` instance for `Response`
--

View File

@ -1,4 +1,3 @@
{-# LANGUAGE CPP #-}
module Servant.QuickCheck.Internal.ErrorTypes where
import Control.Exception (Exception (..))
@ -9,10 +8,9 @@ import Data.Typeable (Typeable)
import GHC.Generics (Generic)
import qualified Network.HTTP.Client as C
import Network.HTTP.Types (Header, statusCode)
import Prelude.Compat
import Text.PrettyPrint
import Prelude.Compat hiding ((<>))
data PredicateFailure
= PredicateFailure T.Text (Maybe C.Request) (C.Response LBS.ByteString)
deriving (Typeable, Generic)

View File

@ -2,6 +2,7 @@
{-# LANGUAGE PolyKinds #-}
module Servant.QuickCheck.Internal.HasGenRequest where
import Data.Monoid ((<>))
import Data.String (fromString)
import Data.String.Conversions (cs)
import GHC.TypeLits (KnownSymbol, Nat, symbolVal)
@ -63,17 +64,21 @@ instance (KnownSymbol path, HasGenRequest b) => HasGenRequest (path :> b) where
(oldf, old) = genRequest (Proxy :: Proxy b)
new = cs $ symbolVal (Proxy :: Proxy path)
#if MIN_VERSION_servant(0,11,0)
instance HasGenRequest EmptyAPI where
genRequest _ = (0, error "EmptyAPIs cannot be queried.")
#endif
#if MIN_VERSION_servant(0,12,0)
instance HasGenRequest api => HasGenRequest (Summary d :> api) where
genRequest _ = genRequest (Proxy :: Proxy api)
instance HasGenRequest api => HasGenRequest (Description d :> api) where
genRequest _ = genRequest (Proxy :: Proxy api)
#endif
instance (Arbitrary c, HasGenRequest b, ToHttpApiData c )
=> HasGenRequest (Capture' mods x c :> b) where
=> HasGenRequest (Capture x c :> b) where
genRequest _ = (oldf, do
old' <- old
new' <- toUrlPiece <$> new
@ -82,6 +87,7 @@ instance (Arbitrary c, HasGenRequest b, ToHttpApiData c )
(oldf, old) = genRequest (Proxy :: Proxy b)
new = arbitrary :: Gen c
#if MIN_VERSION_servant(0,8,0)
instance (Arbitrary c, HasGenRequest b, ToHttpApiData c )
=> HasGenRequest (CaptureAll x c :> b) where
genRequest _ = (oldf, do
@ -92,12 +98,13 @@ instance (Arbitrary c, HasGenRequest b, ToHttpApiData c )
where
(oldf, old) = genRequest (Proxy :: Proxy b)
new = arbitrary :: Gen [c]
#endif
instance (Arbitrary c, KnownSymbol h, HasGenRequest b, ToHttpApiData c)
=> HasGenRequest (Header' mods h c :> b) where
=> HasGenRequest (Header h c :> b) where
genRequest _ = (oldf, do
old' <- old
new' <- toUrlPiece <$> new -- TODO: generate lenient or/and optional
new' <- toUrlPiece <$> new
return $ \burl -> let r = old' burl in r {
requestHeaders = (hdr, cs new') : requestHeaders r })
where
@ -106,9 +113,9 @@ instance (Arbitrary c, KnownSymbol h, HasGenRequest b, ToHttpApiData c)
new = arbitrary :: Gen c
instance (AllMimeRender x c, Arbitrary c, HasGenRequest b)
=> HasGenRequest (ReqBody' mods x c :> b) where
=> HasGenRequest (ReqBody x c :> b) where
genRequest _ = (oldf, do
old' <- old -- TODO: generate lenient
old' <- old
new' <- new
(ct, bd) <- elements $ allMimeRender (Proxy :: Proxy x) new'
return $ \burl -> let r = old' burl in r {
@ -120,9 +127,9 @@ instance (AllMimeRender x c, Arbitrary c, HasGenRequest b)
new = arbitrary :: Gen c
instance (KnownSymbol x, Arbitrary c, ToHttpApiData c, HasGenRequest b)
=> HasGenRequest (QueryParam' mods x c :> b) where
=> HasGenRequest (QueryParam x c :> b) where
genRequest _ = (oldf, do
new' <- new -- TODO: generate lenient or/and optional
new' <- new
old' <- old
return $ \burl -> let r = old' burl
newExpr = param <> "=" <> cs (toQueryParam new')
@ -168,15 +175,6 @@ instance (ReflectMethod method)
, method = reflectMethod (Proxy :: Proxy method)
})
instance (ReflectMethod method)
=> HasGenRequest (NoContentVerb (method :: k)) where
genRequest _ = (1, return $ \burl -> defaultRequest
{ host = cs $ baseUrlHost burl
, port = baseUrlPort burl
, secure = baseUrlScheme burl == Https
, method = reflectMethod (Proxy :: Proxy method)
})
instance (HasGenRequest a) => HasGenRequest (RemoteHost :> a) where
genRequest _ = genRequest (Proxy :: Proxy a)

View File

@ -11,7 +11,7 @@ import Data.CaseInsensitive (foldCase, foldedCase, mk)
import Data.Either (isRight)
import Data.List.Split (wordsBy)
import Data.Maybe (fromMaybe, isJust)
import Data.Semigroup (Semigroup (..))
import Data.Monoid ((<>))
import qualified Data.Text as T
import Data.Time (UTCTime, defaultTimeLocale, parseTimeM,
rfc822DateFormat)
@ -84,13 +84,15 @@ notLongerThan maxAllowed
-- /Since 0.0.0.0/
onlyJsonObjects :: ResponsePredicate
onlyJsonObjects
= ResponsePredicate (\resp -> do
case lookup "content-type" (first foldedCase <$> responseHeaders resp) of
Nothing -> return ()
Just ctype -> when ("application/json" `SBS.isPrefixOf` ctype) $ do
case (decode (responseBody resp) :: Maybe Object) of
Nothing -> throw $ PredicateFailure "onlyJsonObjects" Nothing resp
Just _ -> return ())
= ResponsePredicate (\resp -> case go resp of
Nothing -> throw $ PredicateFailure "onlyJsonObjects" Nothing resp
Just () -> return ())
where
go r = do
ctyp <- lookup "content-type" (first foldedCase <$> responseHeaders r)
when ("application/json" `SBS.isPrefixOf` ctyp) $ do
(_ :: Object) <- decode (responseBody r)
return ()
-- | __Optional__
--
@ -187,15 +189,14 @@ getsHaveLastModifiedHeader
notAllowedContainsAllowHeader :: RequestPredicate
notAllowedContainsAllowHeader
= RequestPredicate $ \req mgr -> do
let reqs = [ req { method = renderStdMethod m } | m <- [minBound .. maxBound]
, renderStdMethod m /= method req ]
resp <- mapM (flip httpLbs mgr) reqs
case filter pred' (zip reqs resp) of
(x:_) -> throw $ PredicateFailure "notAllowedContainsAllowHeader" (Just $ fst x) (snd x)
resp <- mapM (flip httpLbs mgr) $ [ req { method = renderStdMethod m }
| m <- [minBound .. maxBound ]
, renderStdMethod m /= method req ]
case filter pred' resp of
(x:_) -> throw $ PredicateFailure "notAllowedContainsAllowHeader" (Just req) x
[] -> return resp
where
pred' (_, resp) = responseStatus resp == status405 && not (hasValidHeader "Allow" go resp)
pred' resp = responseStatus resp == status405 && not (hasValidHeader "Allow" go resp)
where
go x = all (\y -> isRight $ parseMethod $ SBSC.pack y)
$ wordsBy (`elem` (", " :: [Char])) (SBSC.unpack x)
@ -376,12 +377,9 @@ newtype ResponsePredicate = ResponsePredicate
{ getResponsePredicate :: Response LBS.ByteString -> IO ()
} deriving (Generic)
instance Semigroup ResponsePredicate where
ResponsePredicate a <> ResponsePredicate b = ResponsePredicate $ \x -> a x >> b x
instance Monoid ResponsePredicate where
mempty = ResponsePredicate $ const $ return ()
mappend = (<>)
ResponsePredicate a `mappend` ResponsePredicate b = ResponsePredicate $ \x -> a x >> b x
-- | A predicate that depends on both the request and the response.
--
@ -393,11 +391,7 @@ newtype RequestPredicate = RequestPredicate
-- TODO: This isn't actually a monoid
instance Monoid RequestPredicate where
mempty = RequestPredicate (\r m -> httpLbs r m >>= \x -> return ([x]))
mappend = (<>)
-- TODO: This isn't actually a monoid
instance Semigroup RequestPredicate where
RequestPredicate a <> RequestPredicate b = RequestPredicate $ \r mgr ->
RequestPredicate a `mappend` RequestPredicate b = RequestPredicate $ \r mgr ->
liftM2 (<>) (a r mgr) (b r mgr)
-- | A set of predicates. Construct one with 'mempty' and '<%>'.
@ -406,13 +400,10 @@ data Predicates = Predicates
, responsePredicates :: ResponsePredicate
} deriving (Generic)
instance Semigroup Predicates where
a <> b = Predicates (requestPredicates a <> requestPredicates b)
(responsePredicates a <> responsePredicates b)
instance Monoid Predicates where
mempty = Predicates mempty mempty
mappend = (<>)
a `mappend` b = Predicates (requestPredicates a <> requestPredicates b)
(responsePredicates a <> responsePredicates b)
class JoinPreds a where
joinPreds :: a -> Predicates -> Predicates

View File

@ -2,7 +2,7 @@
{-# LANGUAGE CPP #-}
module Servant.QuickCheck.Internal.QuickCheck where
import Control.Concurrent (tryReadMVar, newEmptyMVar, tryPutMVar)
import Control.Concurrent (modifyMVar_, newMVar, readMVar)
import Control.Monad (unless)
import qualified Data.ByteString.Lazy as LBS
import Data.Proxy (Proxy)
@ -11,9 +11,6 @@ import Network.Wai.Handler.Warp (withApplication)
import Prelude.Compat
import Servant (Context (EmptyContext), HasServer,
Server, serveWithContext)
#if MIN_VERSION_servant_server(0,18,0)
import Servant (DefaultErrorFormatters, ErrorFormatters, HasContextEntry, type (.++))
#endif
import Servant.Client (BaseUrl (..), Scheme (..))
import System.IO.Unsafe (unsafePerformIO)
import Test.Hspec (Expectation, expectationFailure)
@ -40,11 +37,7 @@ withServantServer api = withServantServerAndContext api EmptyContext
-- application.
--
-- /Since 0.0.0.0/
#if MIN_VERSION_servant_server(0,18,0)
withServantServerAndContext :: (HasServer a ctx, HasContextEntry (ctx .++ DefaultErrorFormatters) ErrorFormatters)
#else
withServantServerAndContext :: HasServer a ctx
#endif
=> Proxy a -> Context ctx -> IO (Server a) -> (BaseUrl -> IO r) -> IO r
withServantServerAndContext api ctx server t
= withApplication (return . serveWithContext api ctx =<< server) $ \port ->
@ -80,29 +73,21 @@ serversEqual api burl1 burl2 args req = do
let reqs = (\f -> (f burl1, f burl2)) <$> runGenRequest api
-- This MVar stuff is clunky! But there doesn't seem to be an easy way to
-- return results when a test fails, since an exception is throw.
deetsMVar <- newEmptyMVar
deetsMVar <- newMVar $ error "should not be called"
r <- quickCheckWithResult args { chatty = False } $ monadicIO $ forAllM reqs $ \(req1, req2) -> do
resp1 <- run $ C.httpLbs (noCheckStatus req1) defManager
resp2 <- run $ C.httpLbs (noCheckStatus req2) defManager
unless (getResponseEquality req resp1 resp2) $ do
monitor (counterexample "hi" )
_ <- run $ tryPutMVar deetsMVar $ ServerEqualityFailure req1 resp1 resp2
run $ modifyMVar_ deetsMVar $ const $ return $
ServerEqualityFailure req1 resp1 resp2
assert False
case r of
Success {} -> return ()
Failure{..} -> do
mx <- tryReadMVar deetsMVar
case mx of
Just x ->
expectationFailure $ "Failed:\n" ++ show x
Nothing ->
expectationFailure $ "We failed to record a reason for failure: " <> show r
Failure{..} -> readMVar deetsMVar >>= \x -> expectationFailure $ "Failed:\n" ++ show x
GaveUp { numTests = n } -> expectationFailure $ "Gave up after " ++ show n ++ " tests"
NoExpectedFailure {} -> expectationFailure "No expected failure"
#if MIN_VERSION_QuickCheck(2,12,0)
#else
InsufficientCoverage {} -> expectationFailure "Insufficient coverage"
#endif
-- | Check that a server satisfies the set of properties specified.
--
@ -125,61 +110,37 @@ serversEqual api burl1 burl2 args req = do
-- /Since 0.0.0.0/
serverSatisfies :: (HasGenRequest a) =>
Proxy a -> BaseUrl -> Args -> Predicates -> Expectation
serverSatisfies api = serverSatisfiesMgr api defManager
-- | Check that a server satisfies the set of properties specified, and
-- accept a 'Manager' for running the HTTP requests through.
--
-- See 'serverSatisfies' for more details.
--
-- @since 0.0.7.2
serverSatisfiesMgr :: (HasGenRequest a) =>
Proxy a -> C.Manager -> BaseUrl -> Args -> Predicates -> Expectation
serverSatisfiesMgr api manager burl args preds = do
serverSatisfies api burl args preds = do
let reqs = ($ burl) <$> runGenRequest api
deetsMVar <- newEmptyMVar
deetsMVar <- newMVar $ error "should not be called"
r <- quickCheckWithResult args { chatty = False } $ monadicIO $ forAllM reqs $ \req -> do
v <- run $ finishPredicates preds (noCheckStatus req) manager
_ <- run $ tryPutMVar deetsMVar v
case v of
Just _ -> assert False
_ -> return ()
v <- run $ finishPredicates preds (noCheckStatus req) defManager
run $ modifyMVar_ deetsMVar $ const $ return v
case v of
Just _ -> assert False
_ -> return ()
case r of
Success {} -> return ()
Failure {..} -> do
mx <- tryReadMVar deetsMVar
case mx of
Just x ->
expectationFailure $ "Failed:\n" ++ show x
Nothing ->
expectationFailure $ "We failed to record a reason for failure: " <> show r
Failure{..} -> readMVar deetsMVar >>= \x -> expectationFailure $
"Failed:\n" ++ show x
GaveUp { numTests = n } -> expectationFailure $ "Gave up after " ++ show n ++ " tests"
NoExpectedFailure {} -> expectationFailure $ "No expected failure"
#if MIN_VERSION_QuickCheck(2,12,0)
#else
InsufficientCoverage {} -> expectationFailure "Insufficient coverage"
#endif
InsufficientCoverage {} -> expectationFailure $ "Insufficient coverage"
serverDoesntSatisfy :: (HasGenRequest a) =>
Proxy a -> BaseUrl -> Args -> Predicates -> Expectation
serverDoesntSatisfy api = serverDoesntSatisfyMgr api defManager
serverDoesntSatisfyMgr :: (HasGenRequest a) =>
Proxy a -> C.Manager -> BaseUrl -> Args -> Predicates -> Expectation
serverDoesntSatisfyMgr api manager burl args preds = do
serverDoesntSatisfy api burl args preds = do
let reqs = ($ burl) <$> runGenRequest api
r <- quickCheckWithResult args $ monadicIO $ forAllM reqs $ \req -> do
v <- run $ finishPredicates preds (noCheckStatus req) manager
v <- run $ finishPredicates preds (noCheckStatus req) defManager
assert $ not $ null v
case r of
Success {} -> return ()
GaveUp { numTests = n } -> expectationFailure $ "Gave up after " ++ show n ++ " tests"
Failure { output = m } -> expectationFailure $ "Failed:\n" ++ show m
NoExpectedFailure {} -> expectationFailure $ "No expected failure"
#if MIN_VERSION_QuickCheck(2,12,0)
#else
InsufficientCoverage {} -> expectationFailure "Insufficient coverage"
#endif
InsufficientCoverage {} -> expectationFailure $ "Insufficient coverage"
noCheckStatus :: C.Request -> C.Request
#if MIN_VERSION_http_client(0,5,0)

6
stack-lts-6.yaml Normal file
View File

@ -0,0 +1,6 @@
resolver: lts-6.30
packages:
- '.'
extra-deps: []
flags: {}
extra-package-dbs: []

6
stack-lts-7.yaml Normal file
View File

@ -0,0 +1,6 @@
resolver: lts-7.19
packages:
- '.'
extra-deps: []
flags: {}
extra-package-dbs: []

6
stack-lts-9.yaml Normal file
View File

@ -0,0 +1,6 @@
resolver: lts-9.1
packages:
- '.'
extra-deps: []
flags: {}
extra-package-dbs: []

View File

@ -1,10 +1,10 @@
resolver: nightly-2018-09-03
resolver: lts-8.4
packages:
- '.'
extra-deps:
- hspec-discover-2.5.6
- hspec-core-2.5.6
- hspec-2.5.6
- QuickCheck-2.12
- hspec-2.4.4
- hspec-core-2.4.4
- hspec-discover-2.4.4
- quickcheck-io-0.2.0
flags: {}
extra-package-dbs: []

View File

@ -17,13 +17,25 @@ import qualified Text.Blaze.Html as Blaze
import qualified Text.Blaze.Html5 as Blaze5
import Test.Hspec (Spec, context, describe, it, shouldBe,
shouldContain)
import Test.Hspec.Core.Spec (Arg, Example, Result (..), ResultStatus (..),
defaultParams, safeEvaluateExample)
import Test.Hspec.Core.Spec (Arg, Example, Result (..),
defaultParams)
import Test.QuickCheck.Gen (generate, unGen)
import Test.QuickCheck.Random (mkQCGen)
import Servant.Test.ComprehensiveAPI (comprehensiveAPIWithoutStreamingOrRaw)
#if MIN_VERSION_servant(0,8,0)
import Servant.API.Internal.Test.ComprehensiveAPI (comprehensiveAPIWithoutRaw)
#else
import Servant.API.Internal.Test.ComprehensiveAPI (ComprehensiveAPI,
comprehensiveAPI)
#endif
#if MIN_VERSION_hspec(2,4,0)
import Test.Hspec.Core.Spec (safeEvaluateExample)
#else
import Control.Exception (try)
import Test.Hspec.Core.Spec (evaluateExample)
#endif
import Servant.QuickCheck
import Servant.QuickCheck.Internal (genRequest, runGenRequest,
@ -128,10 +140,6 @@ onlyJsonObjectSpec = describe "onlyJsonObjects" $ do
withServantServerAndContext octetAPI ctx serverOctetAPI $ \burl ->
serverSatisfies octetAPI burl args (onlyJsonObjects <%> mempty)
it "does not fail when there is no content-type" $ do
withServantServerAndContext api2 ctx serverFailing $ \burl ->
serverSatisfies api2 burl args (onlyJsonObjects <%> mempty)
notLongerThanSpec :: Spec
notLongerThanSpec = describe "notLongerThan" $ do
@ -149,7 +157,7 @@ isComprehensiveSpec :: Spec
isComprehensiveSpec = describe "HasGenRequest" $ do
it "has instances for all 'servant' combinators" $ do
let _g = genRequest comprehensiveAPIWithoutStreamingOrRaw
let _g = genRequest comprehensiveAPIWithoutRaw
True `shouldBe` True -- This is a type-level check
deepPathSpec :: Spec
@ -273,9 +281,6 @@ server2 = return $ return 1
server3 :: IO (Server API2)
server3 = return $ return 2
serverFailing :: IO (Server API2)
serverFailing = return . throwError $ err405
-- With Doctypes
type HtmlDoctype = Get '[HTML] Blaze.Html
@ -344,14 +349,27 @@ ctx = BasicAuthCheck (const . return $ NoSuchUser) :. EmptyContext
-- Utils
------------------------------------------------------------------------------
evalExample :: (Example e, Arg e ~ ()) => e -> IO EvalResult
#if MIN_VERSION_hspec(2,4,0)
evalExample e = do
r <- safeEvaluateExample e defaultParams ($ ()) progCallback
case resultStatus r of
Success -> return $ AllGood
Failure _ reason -> return $ FailedWith $ show reason
Pending {} -> error "should not happen"
case r of
Left err -> return $ AnException err
Right Success -> return $ AllGood
Right (Failure _ reason) -> return $ FailedWith $ show reason
Right (Pending _) -> error "should not happen"
where
progCallback _ = return ()
#else
evalExample e = do
r <- try $ evaluateExample e defaultParams ($ ()) progCallback
case r of
Left err -> return $ AnException err
Right Success -> return $ AllGood
Right (Fail _ reason) -> return $ FailedWith reason
Right (Pending _) -> error "should not happen"
where
progCallback _ = return ()
#endif
data EvalResult
= AnException SomeException
@ -369,3 +387,8 @@ noOfTestCases = 20000
#else
noOfTestCases = 1000
#endif
#if !MIN_VERSION_servant(0,8,0)
comprehensiveAPIWithoutRaw :: Proxy ComprehensiveAPI
comprehensiveAPIWithoutRaw = comprehensiveAPI
#endif