Skip to content

Commit

Permalink
Add and improve tests. (#19)
Browse files Browse the repository at this point in the history
* Run all the modules containing a main.

* Fix the path of the executed module in Nimble file's test target.

* Print the command line currently executed on the console when running tests.

* Add a test suite to all the modules.

* Implement the IO monad. (#12)

* Add composition functions.

* Use composition functions in 'optional' module.

* Add the IO monad.

* Use the IO monad in the 'optional' module tests.

* Use an assert instead of the 'not nil' annotation.

* Implement the "close" event for a stream. (#14)

* Implement the reader monad.

* Bump Nim version to 1.0.6.

* Reorganize the modules in folders.

* Remove unused 'lambda' module.

* Rename 'loopstates' module to 'loopsteps'.

* Add 'doNothing' function in 'utils/unit'.

* Add aliases for 'as' explicit conversion functions in 'utils/convert'.

* Add 'utils/variables' module.

* Add lenses from optics in functional programming.

* Add 'loopedcondition' module.

* Add 'loop' module.

* Put step types for 'stream' implementation in 'stream/streamsteps'.

* Use 'loop' module to implement  a stream.

* Use 'utils/variables' in 'loop/loopedcondition'.

* Implement 'skip' in 'stream'.

* Add 'any', 'all' and 'none' matchers for 'stream'.

* Simplify 'chain' proc implementation in 'optics/plens'.

* Make unit tests' names more meaningful in 'optics/lens'.

* optics/lenslaws:
  - Add a template to check all the lens laws for a lens at once.
  - Add tuple types to be passed as the template parameters.
  - Make the unit tests' names more meaningful.

optics/lens_test_common:
  - Remove unnecessary procs.

* optics/focus:
  - Remove the 'noSideEffect' constraint on 'read', 'write', modify' procs.
  - Add API to directly read/write/modify a state instead of going through 'focusOn'.

* optics/lens_test_common:
  - Use a shorter way to get a structure member's type.

* Bump Nim version to '1.2.0'.

* Move 'utils/predicate' in the 'monad' folder.

* - Rename the 'loop/loopedcondition' module to 'loop/loopscope'.
- Add some "real" tests:
  - Check the lens laws for the 2 public lenses.
  - Rename the 'wrapSteps' procs to 'mapSteps'.

* ./loop:
  - Rename the 'wrapSteps' procs to 'mapSteps'.
  - Add 'takeWhile' proc.

loop/loopsteps:
  - Add 'TakeWhileStep' type.

* ./stream:
  - Rename the 'OnCloseCallBack' type to 'OnCloseEvent'.
  - Rename the 'wrapSteps' proc to 'mapSteps'.

* optics/lenslaws :
  -Move the "constructor" procs at the top of the module.

* monad/identity:
  - Remove the test for the 'itself' proc.

* Add API to call an anonymous proc.

* utils/call:
  - Make "call(() -> T)" a proc instead of a template.

* Add API to verify the monad laws against a type.

* monad/io:
- Check the monad laws for "IO[T]".

* utils/proctypes:
- Add API to get the return type of a proc type or instance.

* monad/optional:
  - Cosmetic changes.

* monad/io:
  - Add a test to check if "IO[T]" can be used at compile-time.

* - monad/monadlaws:
  - Remove the "Monad" concept as it can not be implemented currently.
  - Document the module.
- monad/lazymonadlaws:
  - Document the module.

* - monad/[io, optional, reader]:
  - Test these monads against the monad laws.

* - optics/plens:
  - Document the module.

* - lens/lenslaws:
  - Make the single law spec types' name shorter.
- loop/loopscope:
  - Add a short documentation for the module.
  - Change the "initial" parameter type of "run".

* - utils/call:
  - Overload the "call" proc with variants that accept a proc with a different calling convention.

* - utils/proctypes:
  - Fully parameterize the unit tests.

* - loop/loopscope:
  - Change the description of some of the tests.

* Implement partial function application in 'utils/partialprocs'.

* Add aliases to common binary operators in 'utils/operators'.

* - utils:
  - Remove the import of "utils/lambda".

* Remove unused "monad/state".

* - loopscope:
  - Add API to run the loop once.
  - Use partial function application from "utils/partialprocs".

* - loop:
  - Rename the loop scope lens to just "scope".
  - Implement "dropWhile".
  - Implement "runOnce".
  - Test the lenses against the lens laws.
  - Use partial function application from "utils/partialprocs".

* - monad/predicate:
  - Use partial function application from "utils/partialprocs".

* - stream:
  - Give the "initialStep" member its own type -> "Initializer[S]".
  - Change the return type of "skip" and "dropWhile".
  - Simplify the implementation of "takeWhile", "dropWhile" and "skip".
  - Use partial function application from "utils/partialprocs".

* - nim_iterator_stream_experiment, monad, utils:
  - Remove export statements.
  - Delete "monad" and "utils" modules.

* - nim_iterator_stream_experiment:
  - Make the test runner walk over the modules recursively.

* Add an alias to "() =>". (#16)

* - utils/lambda:
  - Add an alias "() =>".

* - loop/loopscope, loop, stream:
  - Use "utils/lambda" to remove a level of indentation.

* Delete "./chain" and "./io".

* Add more tests. (#18)

* - loop/loopsteps:
  - Check the lens laws for the public lenses.

* - stream/streamsteps:
  - Check the lens laws for the exported lenses.

* - utils/partialprocs:
  - Move general utils for "NimNode"s in "utils/nimnodes".

* - utils/operators:
  - Add a "plus1" proc.

* - monad/reader:
  - Use "utils/call".

* - monad/io:
  - Use "monad/reader" for "bracket"'s implementation.
  - Make the "doTest" template generate a proc in the compile-time execution test.

* - loop/loopscope:
  - Make "RunOnceResult" an opaqure object.
  - Add lenses for "RunOnceResult".

* - loop:
  - Use the lenses for "RunOnceResult".

* - utils/reducer:
  - Add a couple of utils for reducers.
- stream:
  - Use "utils/reducer".
  - Add a test to check whether one can stream NimNodes.

* - stream:
  - Do not ignore the result in "reduce".

* - loop/loopscope:
  - Add tests for RunOnceResult's lenses.
  - Add a test to check for compile time execution of a LoopScope.
  - Add tests for "runOnce" and "breakIf".

* - monad/io:
  - Rewrite the test for "bracket".

* - utils/ifelse:
  - Add a test for "ifElse".

* - monad/predicate:
  - Add a proc to map an "ifElse" to a predicate.
  - Add a test for "ifElse".

* - monad/io:
  - Use "chain" instead of "map" whenever possible.

* - monad/monadlaws:
  - Update module documentation on tested monad type requirements.

* - monad/optional:
  - Remove the tests for the constructors, "ifSome" and "ifNone".
  - Add tests to check whether "Nilable" matches the right types.
  - Add tests to check the procs that raise an exception.
  - Rewrite "filter" tests.

* - monad/reader:
  - Remove "local" test.
  - Remove an unnecessary test for "ask".

* - monad/lazymonadlows:
  - Specify lazy monad laws' requirements more precisely.

* - monad/io:
  - Simplify the compile time execution test.

* - monad/[optional, reader]:
  - Add a compile time execution test.

* - utils/[call, ifelse, partialprocs, unit]:
  - Unify the test style when possible.

* - optics/lenslaws:
  - Export "monad/reader" so that other modules have not to import it.

* - loop/loopscope:
  - Add procs to create an empty "LoopScope" or an infinite one.
  - Add tests for the procs mentioned above.
- loop/loopsteps:
  - Move the step types to "stream/streamsteps".
- loop:
  - Add a proc to create an empty loop.
  - Remove the "takeWhile" proc. Only a "Stream" can do it.
  - Add "filter" proc, since there is already "map".
  - Add tests for "filter" and "dropWhile".
- stream:
  - Replace "ZeroStep" by "Unit" in "emptyStream" proc.

* - optics/lens_test_common:
  - Move the module in a private folder.
- optics/plens:
  - Rename the "PLensXXX" proc types to "MemberXXX".

* - utils/operators:
  - Rename "succ" and "pred" to "next" and "prev".
- stream/streamsteps:
  - Re-add "EmptyStep" type.
- loop:
  - Remove the "filter" proc.
    It can only be done on a "Stream".
  - Use "let" instead of embedded procs.
  - Remove the old tests and start writing tests that are more similar to the ones in other modules.

* - Move the test suite runner code in the nimble file.
- Make Git ignore the build directory.

* - Add the extension to the name of the output directory when building the test suite.

* - monad/io:
  - Small changes in the module doc.

* - types/somenatural:
  - Add a concept to match uint and range types that start at 0.
- stream, stream/streamsteps:
  - Use "SomeNatural" concept.
- utils/nimnodes:
  - Use an int instead of a Natural for the index type.
- streams/[ast, sequence, slice]:
  - Add API to stream on standard sequential data structures.

* - loop:
  - Remove unused import of "utils/variables".

* - monad/predicate:
  - Show when a variable is read.

* Setup CI to run the test suite with the C, C++ and Node.js backends.

* - utils/variables:
  - Rewrite "modify" and "write" to make the C++ backend work.

* - loop/loopscope:
  - Add a missing dependency.
  - Make the test suite compile with the C++ backend.

* - stream:
  - Make the test suite compile on the JS backend.

* - streams/sequence:
  - Make the test suite compile on the C++ backend.

* - monad/predicate:

- Make the tests compile on the JS backend.

* - Travis CI:

- Allow the JS test job to fail.

* - streams/ast:
  - Add a test to test the "pairs" stream.
- streams/sequence:
  - Add "real" tests.
- streams/slice:
  - Let the user choose the kind of step needed.
  - Add "real" tests.

* - stream:
  - Add a test to check if "takeWhile" can be used at compile time.

* - README.md:
  - Add a newline between the title and the rest.

* - loop:
  - Make the test suite compile on the JS backend.

* - loop/loopscope:
  - Disable the test that expects an overflow error from an infinite loop on the JS backend.
  - Make the lens tests pass.

* - stream:
  - Disable the test that uses "takeWhile" at compile time on the JS backend.

* - stream, streams/slice:
  - Enable the compile time tests even though they do not compile on the JS backend.
- loop/loopscope, streams/slice:
  - Mark the tests that raise an "OverflowError" as skipped on the JS backend.

* - monad/[ion optional, predicate, reader]:
  - Add static qualifier to compile time test parameters when possible.
    Although, the following is not possible in stable Nim yet (nim-lang/Nim#9679).

* - utils/[ifelse, proctypes]:
  - Make the test suite compile on the JS backend.

* - monad/optional: (#20)

- Add "static" qualifier to compile time tests when possible.
  • Loading branch information
thenjip authored Jun 20, 2020
1 parent 88b2594 commit 27c4c4c
Show file tree
Hide file tree
Showing 32 changed files with 1,935 additions and 745 deletions.
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
.nimcache/
nimcache/
nimblecache/
htmldocs/
35 changes: 29 additions & 6 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,38 @@ language: c

os: linux
dist: bionic

sudo: required

services:
- docker

before_install:
- docker pull nimlang/nim

script:
- docker run nimlang/nim nim --version
- docker run -v "$(pwd):/project" -w /project nimlang/nim sh -c "nimble install -dy && nimble test"
env:
global:
- DOCKER_IMG='nimlang/nim:latest-alpine'


_shared_job: &shared_job
before_install:
- docker pull "$DOCKER_IMG"
script:
- docker run "$DOCKER_IMG" nim --version
- docker run -v "$(pwd):/project" -w /project -e NIM_BACKEND="$NIM_BACKEND" "$DOCKER_IMG" sh -c "nimble install -dy && nimble test"


jobs:
include:
- name: Test suite (C)
env: NIM_BACKEND='cc'
<<: *shared_job

- name: Test suite (C++)
env: NIM_BACKEND='cpp'
<<: *shared_job

- name: Test suite (Node.js)
env: NIM_BACKEND='js'
<<: *shared_job

allow_failures:
- env: NIM_BACKEND='js'
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# nim-iterator-stream-experiment

An attempt at providing a replacement for iterators in Nim with an API similar to Java 8 Stream.
163 changes: 143 additions & 20 deletions nim_iterator_stream_experiment.nimble
Original file line number Diff line number Diff line change
@@ -1,32 +1,155 @@
# Package
version = "0.1.0"
author = "thenjip"
description = "An attempt at providing a replacement for closure iterators in Nim with an API similar to Java 8 Stream."
license = "MIT"
srcDir = "src"

version = "0.1.0"
author = "thenjip"
description = "An attempt at providing a replacement for closure iterators in Nim with an API similar to Java 8 Stream."
license = "MIT"
srcDir = "src"
requires "nim >= 1.2.0"



# Dependencies
import std/[options, os, sequtils, strformat, strutils, sugar]



type
AbsolutePath = string
RelativePath = string

Backend {.pure.} = enum
C
Cxx
Js

InvalidEnvVarValueError = object of CatchableError



func newInvalidEnvVarValueError (
name: string;
value: string
): ref InvalidEnvVarValueError =
InvalidEnvVarValueError.newException(fmt"""{name}="{value}"""")


func findFirst [I, T](a: array[I, T]; predicate: I -> bool): Option[I] =
result = I.none()

for i, item in a:
if i.predicate():
return i.some()



func projectName (): string =
const name = "nim_iterator_stream_experiment"

name



proc moduleDir (): RelativePath =
srcDir / projectName()


func nimcacheDirName (): string =
const name = ".nimcache"

name


func nimcacheDir (): AbsolutePath =
const dir = projectDir() / nimcacheDirName()

dir

requires "nim >= 1.2.0"


func backendEnvVarName (): string =
const name = "NIM_BACKEND"

import std/[os, sequtils, strformat, strutils]
name


func nimCmdNames (): array[Backend, string] =
const names = ["cc", "cpp", "js"]

task test, "":
withDir srcDir:
names


func nimCmdName (backend: Backend): string =
nimCmdNames()[backend]


proc readBackendFromEnv (): Option[Backend] {.
raises: [InvalidEnvVarValueError, ValueError]
.} =
let envVarName = backendEnvVarName()

if envVarName.existsEnv():
let
projectName = "nim_iterator_stream_experiment"
cmdElements =
[
"c",
"-r",
projectDir() / srcDir / fmt"{projectName}{ExtSep}nim"
]

cmdElements.foldl([a, b.quoteShell()].join($' '), "").selfExec()
envVarValue = envVarName.getEnv()
backendFound = nimCmdNames().findFirst(b => b.nimCmdName() == envVarValue)

if backendFound.isSome():
backendFound
else:
raise newInvalidEnvVarValueError(envVarName, envVarValue)
else:
Backend.none()



func testTaskDescription (): string =
func backendChoice (): string =
nimCmdNames().`@`().foldl(a & '|' & b)

@[
fmt"""Build the test suite in "{nimcacheDir()}{DirSep}" and run it.""",
fmt"""The backend can be specified in the environment variable "{backendEnvVarName()}=({backendChoice()})"."""
].foldl(a & ' ' & b)



task test, testTaskDescription():
func buildGenDir (module: RelativePath; backend: Backend): AbsolutePath =
let (dir, file) = module.splitPath()

nimcacheDir() / backend.nimCmdName() / dir / file


proc buildCmdLineParts (
module: RelativePath;
backendSupplier: () -> Option[Backend]
): seq[string] =
func handleJsFlags (backend: Backend): seq[string] =
if backend == Backend.Js:
@["-d:nodejs"]
else:
@[]

let
backend = backendSupplier().get(Backend.C)
genDir = module.buildGenDir(backend).quoteShell()
nimCmd = backend.nimCmdName()
shortOptions = @["-r"] & backend.handleJsFlags()
longOptions = @[fmt"--nimcache:{genDir}", fmt"--outdir:{genDir}"]

@[nimCmd].concat(shortOptions, longOptions, @[module])


withDir moduleDir():
for file in system.getCurrentDir().walkDirRec(relative = true):
if file.endsWith(fmt"{ExtSep}nim"):
file
.buildCmdLineParts(readBackendFromEnv)
.foldl(a & $' ' & b.quoteShell())
.selfExec()



task clean_test, """Remove the build directory of the "test" task.""":
let buildDir = nimcacheDir()

if system.existsDir(buildDir):
buildDir.rmDir()
24 changes: 0 additions & 24 deletions src/nim_iterator_stream_experiment.nim

This file was deleted.

Loading

0 comments on commit 27c4c4c

Please sign in to comment.