Skip to content

Commit

Permalink
Prevent export of default data constructor for NonEmptyMap.
Browse files Browse the repository at this point in the history
This change adds a test to check that the default data constructor for
`NonEmptyMap` is not exported.

The default data constructor for 'NonEmptyMap' is not exported, by
design, as the internal data structure has an invariant that must be
preserved across all operations.

Exporting the default constructor would make it possible for functions
in other modules to break the invariant, opening the door to subtle
regressions.
  • Loading branch information
jonathanknowles committed Dec 2, 2020
1 parent 4ca6909 commit b31fa45
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 0 deletions.
2 changes: 2 additions & 0 deletions lib/core/cardano-wallet-core.cabal
Expand Up @@ -257,6 +257,7 @@ test-suite unit
, scrypt
, servant
, servant-server
, should-not-typecheck
, stm
, openapi3 >= 3.0.0.1
, servant-openapi3
Expand Down Expand Up @@ -332,6 +333,7 @@ test-suite unit
Cardano.WalletSpec
Data.Function.UtilsSpec
Data.Map.NonEmpty.StrictSpec
Data.Map.NonEmpty.StrictSpec.TypeErrorSpec
Data.QuantitySpec
Data.Time.TextSpec
Data.Time.UtilsSpec
Expand Down
16 changes: 16 additions & 0 deletions lib/core/src/Data/Map/NonEmpty/Strict/Internal.hs
Expand Up @@ -19,6 +19,22 @@
module Data.Map.NonEmpty.Strict.Internal
(
-- * Map type

-- Important:
--
-- The default data constructor for 'NonEmptyMap' is not exported, by
-- design, as the internal data structure has an invariant that must be
-- preserved across all operations.
--
-- Exporting the default constructor would make it possible for functions
-- outside this module to break the invariant, opening the door to subtle
-- regressions.
--
-- See the definition of 'NonEmptyMap' for more details of the invariant.
--
-- To construct a 'NonEmptyMap', use one of the provided constructors,
-- all of which are tested to check that they respect the invariant.
--
NonEmptyMap

-- * Construction
Expand Down
40 changes: 40 additions & 0 deletions lib/core/test/unit/Data/Map/NonEmpty/StrictSpec/TypeErrorSpec.hs
@@ -0,0 +1,40 @@
{-# OPTIONS_GHC -fdefer-type-errors #-}
{-# OPTIONS_GHC -fno-warn-deferred-out-of-scope-variables #-}
{-# OPTIONS_GHC -fno-warn-deferred-type-errors #-}
{-# OPTIONS_GHC -fno-warn-dodgy-imports #-}
{-# OPTIONS_GHC -fno-warn-unused-imports #-}

module Data.Map.NonEmpty.StrictSpec.TypeErrorSpec
( spec
) where

import Prelude

import Data.Map.NonEmpty.Strict.Internal
( NonEmptyMap (..) )
import Test.Hspec
( Expectation, Spec, describe, it )
import Test.ShouldNotTypecheck
( shouldNotTypecheck )

spec :: Spec
spec = describe "Strict non-empty map type error tests" $

it "Default data constructor is not exported" $
testDefaultDataConstructorNotExported

-- Test that the default data constructor for 'NonEmptyMap' is not exported.
--
-- The default data constructor for 'NonEmptyMap' is not exported, by design,
-- as the internal data structure has an invariant that must be preserved
-- across all operations.
--
-- Exporting the default data constructor would make it possible for functions
-- in external modules to break the invariant, opening the door to subtle
-- regressions.
--
-- See the definition of 'NonEmptyMap' for more details of the invariant.
--
testDefaultDataConstructorNotExported :: Expectation
testDefaultDataConstructorNotExported =
shouldNotTypecheck $ NonEmptyMap ((), ()) mempty
1 change: 1 addition & 0 deletions nix/.stack.nix/cardano-wallet-core.nix

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit b31fa45

Please sign in to comment.