Added basic parser functionality & tests for these functionalites. Split tests in several files
This commit is contained in:
parent
4c1f25e49d
commit
83659e69b4
9 changed files with 504 additions and 12 deletions
249
README.md
249
README.md
|
@ -1,3 +1,250 @@
|
||||||
# RPG-Engine
|
# RPG-Engine
|
||||||
|
|
||||||
Schrijf een game-engine voor een rollenspel
|
Schrijf een game-engine voor een rollenspel
|
||||||
|
|
||||||
|
https://pixel-poem.itch.io/dungeon-assetpuck
|
||||||
|
https://kyrise.itch.io/kyrises-free-16x16-rpg-icon-pack
|
||||||
|
|
||||||
|
# RPG Engine requirements
|
||||||
|
|
||||||
|
## Functional requirements
|
||||||
|
|
||||||
|
- [ ] Parsing of engine configuration file to game object
|
||||||
|
- [ ] Rendering of all game objects (Levels, objects, entities, ...)
|
||||||
|
- [ ] A start menu with the possibility of selecting a level
|
||||||
|
- [ ] An end screen that shows wether or not a player won
|
||||||
|
- [ ] Support for built-in engine functions
|
||||||
|
|
||||||
|
- [ ] Player can move around in grid-world.
|
||||||
|
- [ ] Player can pick up objects.
|
||||||
|
- [ ] Player can use objects.
|
||||||
|
- [ ] Player can loose and gain health points.
|
||||||
|
- [ ] Player can interact with other entities (fight enimies, open doors, ...).
|
||||||
|
- [ ] Player can go to the next level.
|
||||||
|
|
||||||
|
## Not-functional requirements
|
||||||
|
|
||||||
|
- [ ] Use Parsing.
|
||||||
|
- [ ] Use at least one (1) monad transformer.
|
||||||
|
- [ ] Write good and plenty of documentation.:w
|
||||||
|
|
||||||
|
- [ ] Write tests (for example, using HSpec).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Plaats om dingen neer te jotten
|
||||||
|
|
||||||
|
```
|
||||||
|
Play <--- HandleInput
|
||||||
|
|
|
||||||
|
|
|
||||||
|
v
|
||||||
|
Level <--- LoadLevel <--- Parse
|
||||||
|
|
|
||||||
|
|
|
||||||
|
v
|
||||||
|
RenderLevel
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] State paradigma gebruiken om van startscherm naar playscherm naar pause scherm naar endscherm te gaan
|
||||||
|
|
||||||
|
Nuttige links:
|
||||||
|
|
||||||
|
- https://jakewheat.github.io/intro_to_parsing/
|
||||||
|
|
||||||
|
```
|
||||||
|
Jarne — Today at 22:44
|
||||||
|
Da kan hoor en had da eerst, me gloss eeft geen goede text dus...
|
||||||
|
ListDirectory, en er was ook een fuctie takeBaseName
|
||||||
|
```
|
||||||
|
|
||||||
|
# RPG-Engine Documentation
|
||||||
|
|
||||||
|
## Playing the game
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
- Input commands etc
|
||||||
|
- An example playthrough
|
||||||
|
|
||||||
|
## Writing your own stages
|
||||||
|
|
||||||
|
A stage description file, conventionally named `<stage_name>.txt` is a file with a JSON-like format. It is used to describe
|
||||||
|
everything inside a single stage of your game, including anything related to the player, the levels your game contains
|
||||||
|
and what happens in that level. It is essentially the raw representation of the initial state of a single game.
|
||||||
|
|
||||||
|
> Note: At the moment, every game has a single stage description file. Chaining several files together is not possible yet.
|
||||||
|
|
||||||
|
A stage description file consists of several elements.
|
||||||
|
|
||||||
|
| Element | Short description |
|
||||||
|
| --------------- | --------------------------------------------------------------------------------------------------------- |
|
||||||
|
| `Block` | optionally surrounded by `{ ... }`, consists of several `Entry`'s, optionally separated by commas `,` |
|
||||||
|
| `Entry` | is a `Key` - `Value` pair, optionally separated by a colon `:` |
|
||||||
|
| `Key` | is a unique, predefined `String` describing `Value` |
|
||||||
|
| `Value` | is either a `Block` or a `BlockList` or a traditional value, such as `String` or `Int` |
|
||||||
|
| `BlockList` | is a number of `Block`'s, surrounded by `[ ... ]`, separated by commas, can be empty |
|
||||||
|
|
||||||
|
We'll look at the following example to explain these concepts.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
player: {
|
||||||
|
hp: 50,
|
||||||
|
inventory: [
|
||||||
|
{
|
||||||
|
id: "dagger",
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
name: "Dagger",
|
||||||
|
description: "Basic dagger you found somewhere",
|
||||||
|
useTimes: infinite,
|
||||||
|
value: 10,
|
||||||
|
|
||||||
|
actions: {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
levels: [
|
||||||
|
{
|
||||||
|
layout: {
|
||||||
|
| * * * * * *
|
||||||
|
| * s . . e *
|
||||||
|
| * * * * * *
|
||||||
|
},
|
||||||
|
items: [],
|
||||||
|
entities: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
layout: {
|
||||||
|
| * * * * * * * *
|
||||||
|
| * s . . . . e *
|
||||||
|
| * * * * * * * *
|
||||||
|
},
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
id: "key",
|
||||||
|
x: 3,
|
||||||
|
y: 1,
|
||||||
|
name: "Doorkey",
|
||||||
|
description: "Unlocks a secret door",
|
||||||
|
useTimes: 1,
|
||||||
|
value: 0,
|
||||||
|
actions: {
|
||||||
|
[not(inventoryFull())] retrieveItem(key),
|
||||||
|
[] leave()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
entities: [
|
||||||
|
{
|
||||||
|
id: "door",
|
||||||
|
x: 4,
|
||||||
|
y: 1,
|
||||||
|
name: "Secret door",
|
||||||
|
description: "This secret door can only be opened with a key",
|
||||||
|
direction: left,
|
||||||
|
actions: {
|
||||||
|
[inventoryContains(key)] useItem(key),
|
||||||
|
[] leave()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
This stage description file consists of a single `Block`. A stage description file always does. This top level `Block`
|
||||||
|
contains two `Value`s `player` and `levels`, not separated by commas.
|
||||||
|
|
||||||
|
`player` describes a `Block` that represents the player of the game. Its `Entry`s are `hp` (a traditional value) and
|
||||||
|
`inventory` (a `BlockList` of several other `Block`s). They are both separated by commas this time. It is possible for
|
||||||
|
the inventory to be an empty list `[]`.
|
||||||
|
|
||||||
|
`levels` is a `BlockList` that contains all the information to construct your game.
|
||||||
|
|
||||||
|
### `layout` syntax
|
||||||
|
|
||||||
|
If `Key` has the value `layout`, `Value` is none of the types discussed so far. Instead `Layout` is specifically made
|
||||||
|
to describe the layout of a level. This object is surrounded by `{ ... }` and consists of multiple lines, starting with
|
||||||
|
a vertical line `|` and several characters of the following:
|
||||||
|
|
||||||
|
- `x` is an empty tile a.k.a. void.
|
||||||
|
- `.` is a tile walkable by the player.
|
||||||
|
- `*` is a tile not walkable by the player.
|
||||||
|
- `s` is the starting position of the player.
|
||||||
|
- `e` is the exit.
|
||||||
|
|
||||||
|
All characters are interspersed with spaces.
|
||||||
|
|
||||||
|
### `actions` syntax
|
||||||
|
|
||||||
|
If `Key` has the value `actions`, the following changes are important for its `Value`, which in this case is a `Block`
|
||||||
|
with zero or more `Entry`s like so:
|
||||||
|
|
||||||
|
- `Key` has type `ConditionList`.
|
||||||
|
|
||||||
|
A `ConditionList` consists of several `Condition`s, surrounded by `[ ... ]`, separated by commas. A `ConditionList`
|
||||||
|
can be empty. If so, the conditional is always fulfilled.
|
||||||
|
|
||||||
|
A `Condition` is one of the following:
|
||||||
|
|
||||||
|
- `inventoryFull()`: the players inventory is full.
|
||||||
|
- `inventoryContains(objectId)`: the players inventory contains an object with id `objectId`.
|
||||||
|
- `not(condition)`: logical negation of `condition`.
|
||||||
|
|
||||||
|
- `Value` is an `Action`.
|
||||||
|
|
||||||
|
An `Action` is one of the following:
|
||||||
|
|
||||||
|
- `leave()`
|
||||||
|
- `retrieveItem(objectId)`
|
||||||
|
- `useItem(objectId)`
|
||||||
|
- `decreaseHp(entityId, objectId)`
|
||||||
|
- `increasePlayerHp(objectId)`
|
||||||
|
|
||||||
|
### Back to the example
|
||||||
|
|
||||||
|
If we look at the example, all the objects are
|
||||||
|
|
||||||
|
```
|
||||||
|
>Block<
|
||||||
|
Entry = Key ('player') + >Block<
|
||||||
|
Entry = Key ('hp') + Value (50)
|
||||||
|
Entry = Key ('inventory') + >BlockList<
|
||||||
|
length = 1
|
||||||
|
Block
|
||||||
|
Entry = Key ('id') + Value ("dagger")
|
||||||
|
... <several traditional entries like this>
|
||||||
|
Entry = Key ('actions') + empty Block
|
||||||
|
Entry = Key ('levels') + >BlockList<
|
||||||
|
length = 2
|
||||||
|
>Block<
|
||||||
|
Entry = Key ('layout') + Layout
|
||||||
|
<multiple lines that describe the layout>
|
||||||
|
Entry = Key ('items') + empty BlockList
|
||||||
|
Entry = Key ('entities') + empty BlockList
|
||||||
|
>Block<
|
||||||
|
Entry = Key ('layout') + Layout
|
||||||
|
<multiple lines that describe the layout>
|
||||||
|
Entry = Key ('items') + >BlockList<
|
||||||
|
length = 1
|
||||||
|
>Block<
|
||||||
|
Entry = Key ('id') + Value ("key")
|
||||||
|
... <several traditional entries like this>
|
||||||
|
Entry = Key ('actions') + >Block<
|
||||||
|
Entry = >ConditionList< + Action ('retrieveItem(key)')
|
||||||
|
length = 1
|
||||||
|
Condition ('not(inventoryFull())'))
|
||||||
|
Entry = empty ConditionList + Action ('leave()')
|
||||||
|
Entry = Key ('entities') + >BlockList<
|
||||||
|
length = 1
|
||||||
|
>Block<
|
||||||
|
Entry = Key ('id') + Value ("door")
|
||||||
|
... <several traditional entries like this>
|
||||||
|
Entry = Key ('actions') + >Block<
|
||||||
|
Entry = >ConditionList< + Action ('useItem(key)')
|
||||||
|
length = 1
|
||||||
|
Condition ('inventoryContains(key)')
|
||||||
|
Entry = empty ConditionList + Action ('leave()')
|
||||||
|
```
|
132
lib/control/Parse.hs
Normal file
132
lib/control/Parse.hs
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
module Parse where
|
||||||
|
|
||||||
|
-- TODO Maak wrapper module
|
||||||
|
-- TODO This module should not be used by anything except for wrapper module and tests
|
||||||
|
|
||||||
|
import Game
|
||||||
|
import Player
|
||||||
|
import Text.Parsec
|
||||||
|
import Text.Parsec.Char
|
||||||
|
import Text.Parsec.String
|
||||||
|
import Data.List
|
||||||
|
import Data.Maybe
|
||||||
|
import Text.Parsec.Error (Message(UnExpect))
|
||||||
|
|
||||||
|
-- TODO parseFromFile gebruiken
|
||||||
|
|
||||||
|
-- Parser type
|
||||||
|
-- type Parser = Parsec String ()
|
||||||
|
|
||||||
|
-- A wrapper, which takes a parser and some input and returns a
|
||||||
|
-- parsed output.
|
||||||
|
parseWith :: Parser a -> String -> Either ParseError a
|
||||||
|
parseWith parser = parse parser ""
|
||||||
|
|
||||||
|
ignoreWS :: Parser a -> Parser a
|
||||||
|
ignoreWS parser = spaces >> parser
|
||||||
|
|
||||||
|
-- Also return anything that has not yet been parsed
|
||||||
|
parseWithRest :: Parser a -> String -> Either ParseError (a, String)
|
||||||
|
-- fmap (,) over Parser monad and apply to rest
|
||||||
|
parseWithRest parser = parse ((,) <$> parser <*> rest) ""
|
||||||
|
where rest = manyTill anyToken eof
|
||||||
|
|
||||||
|
parseToGame :: Game
|
||||||
|
parseToGame = undefined
|
||||||
|
|
||||||
|
-- Info in between brackets, '(..)', '[..]', '{..}' or '<..>'
|
||||||
|
data Brackets a = Brackets a
|
||||||
|
deriving (Eq, Show)
|
||||||
|
|
||||||
|
parseToPlayer :: Player
|
||||||
|
parseToPlayer = undefined
|
||||||
|
|
||||||
|
-- any words separated by whitespace
|
||||||
|
parseWord :: Parser String
|
||||||
|
parseWord = do many alphaNum
|
||||||
|
|
||||||
|
-- TODO Expand to allow different kinds of brackets, also see Brackets data type.
|
||||||
|
-- TODO Check if brackets match order.
|
||||||
|
-- TODO Allow nested brackets.
|
||||||
|
brackets :: Parser (Brackets String)
|
||||||
|
brackets = do
|
||||||
|
ignoreWS $ char '('
|
||||||
|
e <- ignoreWS $ many1 alphaNum
|
||||||
|
ignoreWS $ char ')'
|
||||||
|
return $ Brackets e
|
||||||
|
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
data Value = String String
|
||||||
|
| Integer Int
|
||||||
|
| Infinite
|
||||||
|
deriving (Show, Eq)
|
||||||
|
|
||||||
|
-- See documentation for more details, only a short description is
|
||||||
|
--provided here.
|
||||||
|
data StructureElement = Block [StructureElement]
|
||||||
|
| Entry String StructureElement-- Key + Value
|
||||||
|
| Regular Value -- Regular value, Integer or String or Infinite
|
||||||
|
| ConditionList [StructureElement]
|
||||||
|
-- TODO
|
||||||
|
| Condition -- inventoryFull() etc.
|
||||||
|
-- TODO
|
||||||
|
| Action -- leave(), useItem(objectId) etc.
|
||||||
|
deriving (Show, Eq)
|
||||||
|
|
||||||
|
-- TODO Add ConditionList and Action
|
||||||
|
structureElement :: Parser StructureElement
|
||||||
|
structureElement = choice [block, regular]
|
||||||
|
|
||||||
|
-- A Block is a list of Entry s
|
||||||
|
block :: Parser StructureElement
|
||||||
|
block = do
|
||||||
|
ignoreWS $ char '{'
|
||||||
|
list <- ignoreWS $ many1 entry
|
||||||
|
ignoreWS $ char '}'
|
||||||
|
return $ Block list
|
||||||
|
|
||||||
|
entry :: Parser StructureElement
|
||||||
|
entry = do
|
||||||
|
key <- ignoreWS $ many1 alphaNum
|
||||||
|
ignoreWS $ char ':'
|
||||||
|
value <- ignoreWS structureElement -- TODO Is this the correct one to use?
|
||||||
|
return $ Entry key value
|
||||||
|
|
||||||
|
regular :: Parser StructureElement
|
||||||
|
regular = do
|
||||||
|
value <- ignoreWS $ choice [integer, valueString, infinite]
|
||||||
|
return $ Regular value
|
||||||
|
|
||||||
|
integer :: Parser Value
|
||||||
|
integer = do
|
||||||
|
value <- ignoreWS $ many1 digit
|
||||||
|
return $ Integer (read value :: Int)
|
||||||
|
|
||||||
|
valueString :: Parser Value
|
||||||
|
valueString = do
|
||||||
|
ignoreWS $ char '"'
|
||||||
|
value <- ignoreWS $ many1 (noneOf ['"'])
|
||||||
|
ignoreWS $ char '"'
|
||||||
|
return $ String value
|
||||||
|
|
||||||
|
infinite :: Parser Value
|
||||||
|
infinite = do
|
||||||
|
ignoreWS $ string "infinite"
|
||||||
|
notFollowedBy alphaNum
|
||||||
|
return Infinite
|
||||||
|
|
||||||
|
conditionList :: Parser StructureElement
|
||||||
|
conditionList = do
|
||||||
|
ignoreWS $ char '['
|
||||||
|
list <- ignoreWS $ many1 condition
|
||||||
|
ignoreWS $ char ']'
|
||||||
|
return $ ConditionList list
|
||||||
|
|
||||||
|
-- TODO
|
||||||
|
condition :: Parser StructureElement
|
||||||
|
condition = undefined
|
||||||
|
|
||||||
|
-- TODO YOU ARE HERE
|
||||||
|
action :: Parser StructureElement
|
||||||
|
action = undefined
|
|
@ -8,11 +8,12 @@ library
|
||||||
hs-source-dirs: lib, lib/control, lib/data, lib/render
|
hs-source-dirs: lib, lib/control, lib/data, lib/render
|
||||||
build-depends:
|
build-depends:
|
||||||
base >= 4.7 && <5,
|
base >= 4.7 && <5,
|
||||||
gloss >= 1.11 && < 1.14, gloss-juicy >= 0.2.3
|
gloss >= 1.11 && < 1.14, gloss-juicy >= 0.2.3,
|
||||||
|
parsec >= 3.1.15.1
|
||||||
exposed-modules:
|
exposed-modules:
|
||||||
RPGEngine,
|
RPGEngine,
|
||||||
-- Control
|
-- Control
|
||||||
Input, InputHandling,
|
Input, InputHandling, Parse,
|
||||||
-- Data
|
-- Data
|
||||||
Game, Internals, Player, State,
|
Game, Internals, Player, State,
|
||||||
-- Render
|
-- Render
|
||||||
|
@ -26,7 +27,11 @@ executable rpg-engine
|
||||||
|
|
||||||
test-suite rpg-engine-test
|
test-suite rpg-engine-test
|
||||||
type: exitcode-stdio-1.0
|
type: exitcode-stdio-1.0
|
||||||
main-is: RPG-Engine-Test.hs
|
main-is: RPGEngineSpec.hs
|
||||||
hs-source-dirs: test
|
hs-source-dirs: test
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
build-depends: base >=4.7 && <5, hspec <= 2.10.6, rpg-engine
|
build-depends: base >=4.7 && <5, hspec <= 2.10.6, hspec-discover, rpg-engine
|
||||||
|
other-modules:
|
||||||
|
InteractionSpec,
|
||||||
|
-- Parsing
|
||||||
|
ParsedToGameSpec, ParserSpec
|
||||||
|
|
|
@ -42,6 +42,7 @@ extra-deps:
|
||||||
#
|
#
|
||||||
# extra-deps: []
|
# extra-deps: []
|
||||||
- gloss-juicy-0.2.3@sha256:0c3bca95237cbf91f8b3b1936a0661f1e0457acd80502276d54d6c5210f88b25,1618
|
- gloss-juicy-0.2.3@sha256:0c3bca95237cbf91f8b3b1936a0661f1e0457acd80502276d54d6c5210f88b25,1618
|
||||||
|
- parsec-3.1.15.1@sha256:8c7a36aaadff12a38817fc3c4ff6c87e3352cffd1a58df640de7ed7a97ad8fa3,4601
|
||||||
|
|
||||||
# Override default flag values for local packages and extra-deps
|
# Override default flag values for local packages and extra-deps
|
||||||
# flags: {}
|
# flags: {}
|
||||||
|
|
9
test/InteractionSpec.hs
Normal file
9
test/InteractionSpec.hs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
module InteractionSpec where
|
||||||
|
|
||||||
|
import Test.Hspec
|
||||||
|
|
||||||
|
spec :: Spec
|
||||||
|
spec = do
|
||||||
|
describe "Player with Inventory" $ do
|
||||||
|
it "TODO: Simple test" $ do
|
||||||
|
pending
|
52
test/ParsedToGameSpec.hs
Normal file
52
test/ParsedToGameSpec.hs
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
module ParsedToGameSpec where
|
||||||
|
|
||||||
|
import Test.Hspec
|
||||||
|
import Parse
|
||||||
|
|
||||||
|
spec :: Spec
|
||||||
|
spec = do
|
||||||
|
describe "Game" $ do
|
||||||
|
it "TODO: Simple game" $ do
|
||||||
|
pending
|
||||||
|
it "TODO: More complex game" $ do
|
||||||
|
pending
|
||||||
|
it "TODO: Game with multiple levels" $ do
|
||||||
|
pending
|
||||||
|
|
||||||
|
describe "Player" $ do
|
||||||
|
it "TODO: Simple player" $ do
|
||||||
|
pending
|
||||||
|
|
||||||
|
describe "Inventory" $ do
|
||||||
|
it "TODO: Empty inventory" $ do
|
||||||
|
pending
|
||||||
|
it "TODO: Singleton inventory" $ do
|
||||||
|
pending
|
||||||
|
it "TODO: Filled inventory" $ do
|
||||||
|
pending
|
||||||
|
|
||||||
|
describe "Items" $ do
|
||||||
|
it "TODO: Simple item" $ do
|
||||||
|
pending
|
||||||
|
-- Check id
|
||||||
|
-- Check x
|
||||||
|
-- Check y
|
||||||
|
-- Check name
|
||||||
|
-- Check description
|
||||||
|
-- Check useTimes
|
||||||
|
-- Check value
|
||||||
|
-- Check actions
|
||||||
|
|
||||||
|
describe "Actions" $ do
|
||||||
|
it "TODO: Simple action" $ do
|
||||||
|
pending
|
||||||
|
|
||||||
|
describe "Entities" $ do
|
||||||
|
it "TODO: Simple entity" $ do
|
||||||
|
pending
|
||||||
|
|
||||||
|
describe "Level" $ do
|
||||||
|
it "TODO: Simple layout" $ do
|
||||||
|
pending
|
||||||
|
it "TODO: Complex layout" $ do
|
||||||
|
pending
|
52
test/ParserSpec.hs
Normal file
52
test/ParserSpec.hs
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
module ParserSpec where
|
||||||
|
|
||||||
|
import Test.Hspec
|
||||||
|
import Parse
|
||||||
|
import Data.Either
|
||||||
|
|
||||||
|
spec :: Spec
|
||||||
|
spec = do
|
||||||
|
describe "Basics of entries" $ do
|
||||||
|
it "can parse integers" $ do
|
||||||
|
let correct = Right $ Regular $ Integer 1
|
||||||
|
correct `shouldBe` parseWith regular "1"
|
||||||
|
it "can parse string" $ do
|
||||||
|
let input = "dit is een string"
|
||||||
|
correct = Right $ Regular $ String input
|
||||||
|
correct `shouldBe` parseWith regular ("\"" ++ input ++ "\"")
|
||||||
|
it "can parse infinite" $ do
|
||||||
|
let correct = Right $ Regular Infinite
|
||||||
|
correct `shouldBe` parseWith regular "infinite"
|
||||||
|
|
||||||
|
let wrong = Right $ Regular Infinite
|
||||||
|
wrong `shouldNotBe` parseWith regular "infinitee"
|
||||||
|
|
||||||
|
it "can parse entries" $ do
|
||||||
|
let input = "id : \"dagger\""
|
||||||
|
correct = Right $ Entry "id" $ Regular $ String "dagger"
|
||||||
|
correct `shouldBe` parseWith entry input
|
||||||
|
|
||||||
|
let input = "x: 0"
|
||||||
|
correct = Right $ Entry "x" $ Regular $ Integer 0
|
||||||
|
correct `shouldBe` parseWith entry input
|
||||||
|
|
||||||
|
let input = "useTimes: infinite"
|
||||||
|
correct = Right $ Entry "useTimes" $ Regular Infinite
|
||||||
|
correct `shouldBe` parseWith entry input
|
||||||
|
|
||||||
|
describe "Special kinds" $ do
|
||||||
|
it "can parse actions" $ do
|
||||||
|
let input = "actions: {}"
|
||||||
|
correct = Right $ Entry "actions" $ Regular Infinite -- TODO Change this
|
||||||
|
correct `shouldBe` parseWith action input
|
||||||
|
|
||||||
|
it "can parse conditions" $ do
|
||||||
|
pending
|
||||||
|
|
||||||
|
it "can parse layouts" $ do
|
||||||
|
pending
|
||||||
|
|
||||||
|
describe "Lists and blocks" $ do
|
||||||
|
it "can parse entities" $ do
|
||||||
|
pending
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
import Test.Hspec
|
|
||||||
|
|
||||||
main :: IO()
|
|
||||||
main = hspec $ do
|
|
||||||
describe "Dummy category" $ do
|
|
||||||
it "Dummy test" $ do
|
|
||||||
0 `shouldBe` 0
|
|
1
test/RPGEngineSpec.hs
Normal file
1
test/RPGEngineSpec.hs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
|
Reference in a new issue