Skip to content

Commit

Permalink
config round 6: sync on ADRs (#14)
Browse files Browse the repository at this point in the history
* break everything to match ADRs

* rework round 1: manifest subtype and tests fixed

* rework: boatConfig + tests

* filemanager + tests

* rework bdd for easier inner tests

* filemanager current implementation tests

* filemanager current implementation + tests
  • Loading branch information
noahehall authored Mar 20, 2023
1 parent d4ba77a commit e946eb6
Show file tree
Hide file tree
Showing 40 changed files with 1,378 additions and 826 deletions.
76 changes: 53 additions & 23 deletions bdd.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2,70 +2,100 @@
## Bdd
## ===
## simple assertions for use with testament

# follow the leader: https://www.chaijs.com/api/bdd/

## - [inspired by chaijs](https://www.chaijs.com/api/bdd/)
# todo: extract this to a separate package
# todo: think through how to auto-clean up stuff created during tests
# ^ think testament auto sets d:testing which can help with this
# ^ also make note about native nimlang procs, e.g. tryRemoveFile returns bool

import std/sugar

export sugar

type TddError* = ref object of CatchableError
## generic error for test driven development

var tddError* = TddError(msg: "TODO: this feature isnt ready yet") ## \
## ready to be raised tddError
## ready to be raised tdd error

type BddDefect = ref object of Defect
## not a tddError, used internally
var failure = BddDefect(msg: "Invalid Test Parameters") ## \
## escape hatch to fail a test early

proc assertCondition(
condition: bool,
matches: bool,
name: string,
msg: string,
): void =
## tests the assertion
## all other methods are sugar for this proc
doAssert condition == matches, name & " -> " & msg

proc itShould*(
msg: string,
name = "test name: ",
condition: bool,
istrue = true
name = "test name: ",
): void =
## asserts condition matches expectation
## prefer creating a test case with bdd
doAssert condition == istrue, name & " -> " & msg
assertCondition condition, true, name, msg

proc itShouldNot*(
msg: string,
condition: bool,
name = "test name: ",
condition: bool
): void =
## asserts condition matches expectation
## prefer creating a test case with bdd
itShould msg, name, condition, false
assertCondition condition, false, name, msg

type What* = enum
## expected result of some condition
should, ## be true
shouldRaise, ## error when called
shouldNot, ## be true
shouldNotRaise, ## error when called
shouldRaise, ## error when called
shouldRaiseMsg, ## when called
shouldNotRaiseMsg, ## but should raise a different msg when called

proc bdd*(caseName: string): (What, string, () -> bool) -> void =
## simple assertions for use with testament
## provide a test name and receive a fn that
## validates condition matches expectation
(what: What, msg: string, condition: () -> bool) => (
case what
of should: itShould msg, caseName, condition()
of shouldNot: itShouldNot msg, caseName, condition()
of shouldRaise, shouldNotRaise:
var didRaise = false
try: discard condition()
except CatchableError: didRaise = true
finally:
if what.ord == shouldRaise.ord: itShould msg, caseName, didRaise
else: itShouldNot msg, caseName, didRaise
of should: itShould msg, condition(), caseName
of shouldNot: itShouldNot msg, condition(), caseName
of
shouldNotRaise,
shouldNotRaiseMsg,
shouldRaise,
shouldRaiseMsg:
var didRaise = false
var msgRaised: string
try: discard condition()
except CatchableError, Defect:
didRaise = true
msgRaised = getCurrentExceptionMsg()
finally:
case what:
of shouldNotRaise: itShouldNot msg, didRaise, caseName
of shouldNotRaiseMsg: itShould msg, didRaise and msgRaised != msg, caseName
of shouldRaise: itShould msg, didRaise, caseName
of shouldRaiseMsg: itShould msg, didRaise and msgRaised == msg, caseName
else: raise failure
)

export sugar

when isMainModule:
proc catchme: bool = raise TddError(msg: "if you can")
proc raiseMsg: bool = raise failure

let it = bdd "bdd tests"
it should, "be true", () => true
it shouldNot, "be true", () => false
it shouldRaise, "error", () => catchme()
it shouldNotRaise, "error", () => true
it shouldNotRaise, "or care about result", () => false
it shouldNotRaiseMsg, "anything but this", () => raiseMsg()
it shouldRaise, "error", () => catchme()
it shouldRaiseMsg, failure.msg, () => raiseMsg()
2 changes: 1 addition & 1 deletion config.nims
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ case getEnv "ENV":
of "DEV":
--assertions:on
--checks:on
--colors:on
# --colors:on # breaks vscode runner?
--debuginfo:on
--declaredLocs:on
--errorMax:0
Expand Down
118 changes: 57 additions & 61 deletions src/boat.dot
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,18 @@ digraph boat {
"std/private/underscored_calls" -> "std/macros";
"std/sugar" -> "std/private/underscored_calls";
"../bdd" -> "std/sugar";
"boat/private/boatConfig" -> "../bdd";
"std/hashes" -> "std/private/since";
"std/tables" -> "std/private/since";
"boat/manifest" -> "../bdd";
"std/os" -> "std/private/since";
"std/strutils" -> "std/parseutils";
"std/math" -> "std/private/since";
"std/bitops" -> "std/macros";
"std/bitops" -> "std/private/since";
"std/bitops" -> "std/private/bitops_utils";
"std/bitops" -> "system/countbits_impl";
"std/math" -> "std/bitops";
"std/math" -> "std/fenv";
"std/algorithm" -> "std/private/since";
"std/tables" -> "std/hashes";
"std/tables" -> "std/math";
"std/tables" -> "std/algorithm";
"std/strutils" -> "std/parseutils";
"std/strutils" -> "std/math";
"std/algorithm" -> "std/private/since";
"std/strutils" -> "std/algorithm";
"std/enumutils" -> "std/macros";
"std/typetraits" -> "std/private/since";
Expand All @@ -57,57 +53,25 @@ digraph boat {
"std/strutils" -> "std/unicode";
"std/strutils" -> "std/private/since";
"std/strutils" -> "std/private/strimpl";
"std/streams" -> "std/private/since";
"std/lexbase" -> "std/strutils";
"std/lexbase" -> "std/streams";
"std/parsejson" -> "std/strutils";
"std/parsejson" -> "std/lexbase";
"std/parsejson" -> "std/streams";
"std/parsejson" -> "std/unicode";
"std/parsejson" -> "std/private/decode_helpers";
"std/json" -> "std/hashes";
"std/json" -> "std/tables";
"std/json" -> "std/strutils";
"std/json" -> "std/lexbase";
"std/json" -> "std/streams";
"std/json" -> "std/macros";
"std/json" -> "std/parsejson";
"std/options" -> "std/typetraits";
"std/json" -> "std/options";
"std/json" -> "std/private/since";
"std/os" -> "std/private/since";
"std/pathnorm" -> "std/osseps";
"std/os" -> "std/strutils";
"std/os" -> "std/pathnorm";
"std/options" -> "std/typetraits";
"std/times" -> "std/strutils";
"std/times" -> "std/math";
"std/times" -> "std/options";
"std/times" -> "std/private/since";
"std/times" -> "std/posix";
"std/os" -> "std/posix";
"std/os" -> "std/times";
"boat/private/boatConfig" -> "std/json";
"boat/private/boatConfig" -> "std/os";
"boat/private/boatConfig" -> "std/strutils";
"std/parsecfg" -> "std/strutils";
"std/parsecfg" -> "std/lexbase";
"std/parsecfg" -> "std/streams";
"std/parsecfg" -> "std/tables";
"std/parsecfg" -> "std/private/decode_helpers";
"std/parsecfg" -> "std/private/since";
"boat/private/boatConfigType" -> "std/parsecfg";
"boat/private/boatConfigType" -> "std/json";
"boat/private/boatConstants" -> "std/os";
"boat/private/boatConstants" -> "std/json";
"boat/private/boatConstants" -> "std/parsecfg";
"std/strformat" -> "std/macros";
"std/strformat" -> "std/parseutils";
"std/strformat" -> "std/unicode";
"std/strformat" -> "std/strutils";
"boat/private/boatErrors" -> "std/strformat";
"boat/private/boatConstants" -> "boat/private/boatErrors";
"boat/private/fileManager" -> "../bdd";
"boat/private/fileManagerUtils" -> "../bdd";
"boat/manifest" -> "std/os";
"boat/manifest" -> "std/strutils";
"boat/private/captainsLogUtils" -> "../bdd";
"std/tables" -> "std/private/since";
"std/hashes" -> "std/private/since";
"std/tables" -> "std/hashes";
"std/tables" -> "std/math";
"std/tables" -> "std/algorithm";
"std/heapqueue" -> "std/private/since";
"std/deques" -> "std/private/since";
"std/deques" -> "std/math";
Expand Down Expand Up @@ -184,25 +148,57 @@ digraph boat {
"std/asyncdispatch" -> "std/strutils";
"std/asyncdispatch" -> "std/asyncfutures";
"std/asyncdispatch" -> "std/posix";
"std/streams" -> "std/private/since";
"std/lexbase" -> "std/strutils";
"std/lexbase" -> "std/streams";
"std/parsejson" -> "std/strutils";
"std/parsejson" -> "std/lexbase";
"std/parsejson" -> "std/streams";
"std/parsejson" -> "std/unicode";
"std/parsejson" -> "std/private/decode_helpers";
"std/json" -> "std/hashes";
"std/json" -> "std/tables";
"std/json" -> "std/strutils";
"std/json" -> "std/lexbase";
"std/json" -> "std/streams";
"std/json" -> "std/macros";
"std/json" -> "std/parsejson";
"std/json" -> "std/options";
"std/json" -> "std/private/since";
"boat/private/captainsLogUtils" -> "std/asyncdispatch";
"boat/private/captainsLogUtils" -> "std/json";
"boat/private/captainsLogUtils" -> "std/os";
"boat/manifest" -> "boat/private/captainsLogUtils";
"std/parsecfg" -> "std/strutils";
"std/parsecfg" -> "std/lexbase";
"std/parsecfg" -> "std/streams";
"std/parsecfg" -> "std/tables";
"std/parsecfg" -> "std/private/decode_helpers";
"std/parsecfg" -> "std/private/since";
"boat/private/boatConfig" -> "std/parsecfg";
"boat/private/boatConfig" -> "std/json";
"boat/private/boatConfig" -> "boat/private/captainsLogUtils";
"std/strformat" -> "std/macros";
"std/strformat" -> "std/parseutils";
"std/strformat" -> "std/unicode";
"std/strformat" -> "std/strutils";
"boat/private/boatErrors" -> "std/strformat";
"boat/private/boatConfig" -> "boat/private/boatErrors";
"boat/private/fileManager" -> "../bdd";
"boat/private/fileManagerUtils" -> "../bdd";
"boat/private/fileManagerUtils" -> "std/asyncdispatch";
"boat/private/fileManagerUtils" -> "std/hashes";
"boat/private/fileManagerUtils" -> "std/json";
"boat/private/fileManagerUtils" -> "std/os";
"boat/private/fileManagerUtils" -> "std/parsecfg";
"boat/private/boatConstants" -> "std/os";
"boat/private/boatConstants" -> "boat/private/boatErrors";
"boat/private/fileManagerUtils" -> "boat/private/boatErrors";
"boat/private/fileManagerUtils" -> "boat/private/boatConstants";
"boat/private/fileManager" -> "boat/private/boatConstants";
"boat/private/fileManager" -> "boat/private/boatErrors";
"boat/private/fileManager" -> "boat/private/fileManagerUtils";
"boat/private/boatConfigType" -> "boat/private/boatConstants";
"boat/private/boatConfigType" -> "boat/private/fileManager";
"boat/private/captainsLogUtils" -> "std/asyncdispatch";
"boat/private/captainsLogUtils" -> "std/json";
"boat/private/captainsLogUtils" -> "std/os";
"boat/private/boatConfig" -> "boat/private/boatConfigType";
"boat/private/boatConfig" -> "boat/private/boatConstants";
"boat/private/boatConfig" -> "boat/private/boatErrors";
"boat/private/boatConfig" -> "boat/private/captainsLogUtils";
"boat/private/boatConfig" -> "boat/private/fileManager";
"boat" -> "boat/private/boatConfig";
"boat/manifest" -> "boat/private/boatConfig";
"boat/manifest" -> "boat/private/boatErrors";
"boat/manifest" -> "boat/private/fileManager";
"boat" -> "boat/manifest";
}
4 changes: 2 additions & 2 deletions src/boat.nim
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
## .. include:: ./readme.rst

import boat/private/boatConfig
import boat/manifest

proc boat*: void = echo "All HANDS! cat o'nine tails! blue peter! OMG... landlubber"

when isMainModule:
let fake = BoatConfig[Config](use: "fake config")
let fake = Manifest(use: "fake config")
debugEcho fake.use
Binary file modified src/boat.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
81 changes: 81 additions & 0 deletions src/boat/manifest.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# import std/[
# json,
# os,
# ]

from ../../bdd import tddError

import std/[os, strutils]

from private/captainsLogUtils import logAction, Action

import private/[
boatConfig,
boatErrors,
fileManager
]

const manifestName* = "manifest.nim.ini" ## \
## the captains manifest must be named manifest.nim.ini

type Manifest* = ref object of BoatConfig
parsed*: Config ## \
## the parsed configuration

method parse*(self: Manifest, path: string = ""): bool =
## parses a local BoatConfig
self.parsed = retrieve[Config](self.parsed, self.usePath path)
result = true

method isValid*(self: Manifest): bool =
## throws if self.use not found, cant be read, or errors during parsing
let pathInfo = self.use.getFileInfo

result = case pathInfo.kind
of pcFile, pcLinkToFile:
if fpUserRead notin pathInfo.permissions: raise filePermissionError
elif not self.use.endsWith manifestName: raise manifestNameError
elif not self.parse: raise configParseError
else: true
of pcDir, pcLinkToDir:
# force directories to use their manifest
self.use = self.use / manifestName
self.isValid


method save*(self: Manifest): bool =
## caches BoatConfig to disk (based on manifest dir) and updates CaptainsLog with path
let fpath = waitFor toDisk[Config](self.parsed, self.use.pathDir)
BoatConfigSave.logAction fpath


method reload*(self: Manifest): bool =
## reloads a configuration from CaptainsLog
raise tddError

method load*(self: Manifest): bool =
## (re)load a Configuration
result =
# if self.use in CaptainsLog ? reload from CaptainsLog
if 1 > 2: raise tddError
else: self.init

method init*(self: Manifest): bool =
# starts with https?
# ends with manifestName?
# check FileManagerUtils.retrieve
# it should contain logic for loading remote manifests
# throw: urls must point to a manifest.nim.ini
result = case self.use.startsWith "https"
of true: raise tddError
else:
try:
if self.isValid and self.save: true
else: raise fileSaveDefect
except CatchableError:
debugEcho repr getCurrentException()
raise fileLoadDefect

when isMainModule:
debugEcho repr Manifest(use: "xyz")
debugEcho repr Manifest(use: "xyz").typeof
Loading

0 comments on commit e946eb6

Please sign in to comment.