diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 103cb57..72221c1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,10 @@ on: pull_request: branches: [ master ] +env: + ARTIFACT_NAME: "linux-clang-15.zip" + CLANG_VERSION: 15 + jobs: build: runs-on: ubuntu-latest @@ -14,29 +18,29 @@ jobs: - name: Checkout std uses: actions/checkout@v2 - - uses: robinraju/release-downloader@v1.5 + - uses: robinraju/release-downloader@v1.9 with: latest: true + preRelease: true repository: ArkScript-lang/Ark - fileName: "linux-clang-11.zip" + fileName: ${{ env.ARTIFACT_NAME }} - name: Set up files shell: bash run: | - unzip linux-clang-11.zip + unzip $ARTIFACT_NAME chmod u+x arkscript *.so lib/*.arkm cp lib/*.arkm ./ - name: Update LLVM compilers shell: bash run: | - version=11 - sudo apt-get install -y clang-${version} lld-${version} libc++-${version}-dev libc++abi-${version}-dev clang-tools-${version} + sudo apt-get install -y clang-${CLANG_VERSION} lld-${CLANG_VERSION} \ + libc++-${CLANG_VERSION}-dev libc++abi-${CLANG_VERSION}-dev \ + clang-tools-${CLANG_VERSION} - name: Tests shell: bash run: | ./arkscript --version - for f in tests/*.ark; do - ./arkscript $f -L ./ - done + ./arkscript tests/all.ark -L ./ diff --git a/Events.ark b/Events.ark index acb7ed3..bf1f2ae 100644 --- a/Events.ark +++ b/Events.ark @@ -1,4 +1,4 @@ -(import "List.ark") +(import std.List) # @brief Allows to register events listeners and emit events # =begin diff --git a/List.ark b/List.ark index 023d45d..5596211 100644 --- a/List.ark +++ b/List.ark @@ -3,7 +3,7 @@ # @param _func the function to call on each element # @details The original list is left unmodified. # =begin -# (import "List.ark") +# (import std.List) # (let collection [1 2 5 12]) # (list:forEach collection (fun (element) { # (print element) @@ -21,7 +21,7 @@ # @param _L the list to iterate over # @details The original list is left unmodified. # =begin -# (import "List.ark") +# (import std.List) # (let collection [1 2 5 12]) # (let p (list:product collection)) # => 120 # =end @@ -38,7 +38,7 @@ # @param _L the list to iterate over # @details The original list is left unmodified. # =begin -# (import "List.ark") +# (import std.List) # (let collection [1 2 5 12]) # (let p (list:sum collection)) # => 20 # =end @@ -51,7 +51,7 @@ (set _index (+ 1 _index))}) _output })) -(import "Math.ark") # needed for math:min, math:max +(import std.Math :min :max) # @brief Drop the first n elements of a list # @param _L the list to work on @@ -101,7 +101,7 @@ # @param _f the predicate # @details The original list is left unmodified. # =begin -# (import "Math.ark") +# (import std.Math) # (print (list:filter [1 2 3 4 5 6 7 8 9] math:even)) # [2 4 6 8] # =end # @author https://github.com/rstefanic diff --git a/Macros.ark b/Macros.ark index a34c0ac..d342478 100644 --- a/Macros.ark +++ b/Macros.ark @@ -1,15 +1,15 @@ -!{-> (arg fn1 ...fn) { - !{if (> (len fn) 0) +($ -> (arg fn1 ...fn) { + ($if (> (len fn) 0) (-> (fn1 arg) ...fn) - (fn1 arg)}}} + (fn1 arg))}) # internal, do not use -!{__suffix-dup (sym x) { - !{if (> x 1) - (__suffix-dup sym (- x 1))} - (symcat sym x)}} +($ __suffix-dup (sym x) { + ($if (> x 1) + (__suffix-dup sym (- x 1))) + (symcat sym x)}) -!{partial (func ...defargs) { - !{bloc (__suffix-dup a (- (argcount func) (len defargs)))} +($ partial (func ...defargs) { + ($ bloc (__suffix-dup a (- (argcount func) (len defargs)))) (fun (bloc) (func ...defargs bloc)) - !{undef bloc}}} + ($undef bloc)}) \ No newline at end of file diff --git a/String.ark b/String.ark index 5d5b0a1..c9d2fd0 100644 --- a/String.ark +++ b/String.ark @@ -135,11 +135,15 @@ (let _pattern_sz (len _pattern)) (while (!= -1 _idx) { + (mut _first_segment (str:slice _out 0 _idx)) + (mut _next_segment (str:slice _out (+ _idx _pattern_sz) (- (len _out) (+ _idx _pattern_sz)))) (set _out (+ - (str:slice _out 0 _idx) + _first_segment _new - (str:slice _out (+ _idx _pattern_sz) (- (len _out) (+ _idx _pattern_sz))))) - (set _idx (str:find _out _pattern))}) + _next_segment)) + (set _idx (str:find _next_segment _pattern)) + (if (!= -1 _idx) + (set _idx (+ _idx (len _first_segment) (len _new))))}) _out })) # @brief Join a list of elements with a given string delimiter diff --git a/Testing.ark b/Testing.ark new file mode 100644 index 0000000..c12d754 --- /dev/null +++ b/Testing.ark @@ -0,0 +1,190 @@ +# internal, do not use +(let _runner (fun (_name _callable) { + (mut _passed 0) + (mut _failed 0) + (mut _failures []) + (let _case_desc "") + (mut _cases []) + (mut _case_pointer 0) + (mut display_cases_success false) + + (let _start_time (time)) + # run test + (_callable) + (let _end_time (time)) + + # no newline, yet + (puts _name) + (if (> _passed 0) + (puts (str:format " - {} ✅" _passed))) + (if (> _failed 0) + (puts (str:format ", {} ❌" _failed))) + + (puts (str:format " in {:2.3f}ms\n" (* 1000 (- _end_time _start_time)))) + + (mut _i 0) + (let _failures_count (len _failures)) + (while (< _i _failures_count) { + (print " " (@ _failures _i)) + (set _i (+ 1 _i))}) + + [_passed _failed]})) + +(let _test_desc (fun (_desc) + (if (empty? _desc) + "" + (str:format " for test '{}'" (head _desc))))) + +# internal, do not use +# Has a _case_desc which also exists (empty) inside _runner so that tests without a +# case won't crash the testing library when trying to access the case name. +# Add the test name to a pile so that we can nicely print all the case names later. +# Update the pointer to current case to its old value later on +(let _case (fun (_case_desc _callable) { + (let _old_pointer _case_pointer) + (append! _cases _case_desc) + (_callable) + (pop! _cases -1) + (set _case_pointer _old_pointer)})) + +# @brief Create a test case with a label to help with debugging when one or more tests fail +# @details Test cases can be nested. +# @param _desc a description for the test, a string +# @param _body test to execute +# =begin +# (test:suite name { +# (test:expect (my_function 1 2 3)) +# (test:case "a description" { +# (test:expect (return_true) "return true"}) +# (test:eq 1 2 "1 is 2, this should fail")}) +# =end +# @author https://github.com/SuperFola +($ test:case (_desc _body) + (_case _desc (fun () {_body}))) + +# internal, do not use +# Until _case_pointer isn't at the end of the pile (where our failing test case's is), +# iterate on the list, writing the case name in a cascade pattern. +# This way if we have CASE A>CASE B>CASE C and no test crashed in A nor in A>B, +# we are still able to display the cascade A>B>C with the correct indentation. +(let _add_case (fun () { + (let _target_len (len _cases)) + (while (< _case_pointer _target_len) { + (mut _indent (* 2 _case_pointer)) + (mut _fmt (if (> _indent 0) (+ "{: <" (toString _indent) "}{}") "{}{}")) + (append! _failures (str:format _fmt "" (@ _cases _case_pointer))) + (set _case_pointer (+ 1 _case_pointer))})})) + +# internal, do not use +# This can only be used within a (nested or not) call to test:suite +# because it updates _failed and _failures, which are defined by +# test:suite call to _runner +(let _report_error (fun (_lhs _rhs _lhs_repr _rhs_repr _desc) { + (set _failed (+ 1 _failed)) + + # If we have a case description AND the pointer isn't up to date, display the case(s)' names + (if (and (not (empty? _case_desc)) (!= _case_pointer (len _cases))) + (_add_case)) + + # Compute global indent for the failing test resume + (let _indent_case_len (* 2 (len _cases))) + (let _indent (if (> _indent_case_len 0) + (str:format (+ "{: <" (toString _indent_case_len) "}") "") + "")) + # Add the error message + (append! _failures (str:format "{}expected '{}' but got '{}'{}" _indent _lhs_repr _rhs_repr (_test_desc _desc))) + + (let _rhs_start (+ (len _lhs_repr) (len "expected ''"))) + (let _lhs_align (len _lhs_repr)) + (let _rhs_align (len _rhs_repr)) + (let _show_expected (!= _lhs_repr (toString _lhs))) + (let _show_real (!= _rhs_repr (toString _rhs))) + + (if _show_real + (append! _failures + (str:format + (+ "{}{: <" (toString (len "expected ")) "}" "{: <" (toString _rhs_start) "}{:~<" (toString _rhs_align) "} {}") + _indent + # to position one char before the first ' surrounding the expected value + "" + # writes the | right under the first ' surrounding the expected value + (if _show_expected "|" "") + # begins the \~~~~ under the real value + (if _show_real "\\" "") + (if _show_real _rhs "")))) + (if _show_expected + (append! _failures + (str:format + (+ "{}{: <" (toString (len "expected ")) "}\\ {}") + _indent + "" + _lhs)))})) + +# internal, do not use +# This can only be used within a (nested or not) call to test:suite +# because it updates _passed, which is defined by test:suite call to _runner +(let _report_success (fun () { + (set _passed (+ 1 _passed)) + (if display_cases_success + (_add_case)) +})) + +# @brief Given a value or function call returning a boolean, generate a test case +# @param _cond the value to test for truthiness +# @param _desc an optional description (string) for the test +# =begin +# (test:suite name { +# (test:expect (my_function 1 2 3)) +# (test:expect (return_true) "return true"}) +# =end +# @author https://github.com/SuperFola +($ test:expect (_cond ..._desc) { + (if (!= true _cond) + { + (set _failed (+ 1 _failed)) + (append! _failures (str:format "{} returned {}{}" ($repr _cond) _cond) (_test_desc _desc))} + (_report_success))}) + +# @brief Compare two values that should be equal and generate a test case +# @param _expected expected value +# @param _expr computed value to test +# @param _desc an optional description (string) for the test +# =begin +# (test:suite name { +# (test:eq 6 (my_function 1 2 3)) +# (test:eq 5 (foo) "foo should return 5")}) +# =end +# @author https://github.com/SuperFola +($ test:eq (_expected _expr ..._desc) { + (if (= _expected _expr) + (_report_success) + (_report_error _expected _expr ($repr _expected) ($repr _expr) _desc))}) + +# @brief Compare two values that should **not** be equal and generate a test case +# @param _unexpected the value we don't want +# @param _value tested value +# @param _desc an optional description (string) for the test +# =begin +# (test:suite name { +# (test:neq 0 (my_function 1 2 3))}) +# =end +# @author https://github.com/SuperFola +($ test:neq (_unexpected _value ..._desc) { + (if (!= _unexpected _value) + (_report_success) + (_report_error _unexpected _value ($repr _unexpected) ($repr _value) _desc))}) + +# @brief Generate the code for a test suite +# @details Create two variables: _name-output (a list: [successes, failures]) and _name-status (boolean, true on success) +# @param _name test name, as an identifier +# @param _body body of the test, a begin block +# =begin +# (test:suite name { +# (set display_cases_success true) # default: false, when true, display all the cases names on success and failures +# (test:eq 6 (my_function 1 2 3)) +# (test:eq 128 (* 8 16))}) +# =end +# @author https://github.com/SuperFola +($ test:suite (_name _body) { + (let (symcat _name "-output") (_runner ($repr _name) (fun () {_body}))) + (let (symcat _name "-status") (= 0 (@ (symcat _name "-output") 1)))}) diff --git a/tests/all.ark b/tests/all.ark new file mode 100644 index 0000000..b37678b --- /dev/null +++ b/tests/all.ark @@ -0,0 +1,10 @@ +(import events-tests) +(import exceptions-tests) +(import functional-tests) +(import lazy-tests) +(import list-tests) +(import macros-tests) +(import math-tests) +(import range-tests) +(import string-tests) +(import switch-tests) \ No newline at end of file diff --git a/tests/events-tests.ark b/tests/events-tests.ark index e759c50..284ebc0 100644 --- a/tests/events-tests.ark +++ b/tests/events-tests.ark @@ -1,40 +1,30 @@ -(import "tests-tools.ark") +(import std.Events) +(import std.Testing) -(import "Events.ark") - -(let events-tests (fun () { - (mut tests 0) - (let start-time (time)) - - (let em (events:manager:make)) +(let em (events:manager:make)) +(test:suite events { # _check_valid tests - (set tests (assert-eq true (em._check_valid (fun () ())) "check_valid" tests)) - (set tests (assert-eq false (em._check_valid 4) "check_valid" tests)) + (test:expect (em._check_valid (fun () ())) "a function is valid") + (test:expect (not (em._check_valid 4))) # on tests (em.on "myType" 4) - (set tests (assert-eq [] em._listeners "listeners empty" tests)) + (test:eq [] em._listeners) (em.on "myType" (fun (_) ())) - (set tests (assert-neq [] em._listeners "listeners with one element" tests)) + (test:neq [] em._listeners) # emit tests - (set tests (assert-eq false (em.emit "emitType") "emit" tests)) + (test:expect (not (em.emit "emitType"))) (em.on "emitType" (fun (_) ())) - (set tests (assert-eq true (em.emit "emitType") "emit" tests)) + (test:expect (em.emit "emitType")) # emitWith tests - (set tests (assert-eq false (em.emitWith 1 "emitWithType") "emitWith" tests)) + (test:expect (not (em.emitWith 1 "emitWithType"))) (em.on "emitWithType" (fun (_) ())) - (set tests (assert-eq true (em.emitWith 2 "emitWithType") "emitWith" tests)) + (test:expect (em.emitWith 2 "emitWithType")) # removeListenersOfType - (set tests (assert-eq false (em.removeListenersOfType "removeType") "removeListenersOfType" tests)) + (test:expect (not (em.removeListenersOfType "removeType"))) (em.on "removeType" (fun (_) ())) - (set tests (assert-eq true (em.removeListenersOfType "removeType") "removeListenersOfType" tests)) - - (recap "Events tests passed" tests (- (time) start-time)) - - tests })) - -(let passed-events (events-tests)) \ No newline at end of file + (test:expect (em.removeListenersOfType "removeType"))}) diff --git a/tests/exceptions-tests.ark b/tests/exceptions-tests.ark index 1f8a490..b58127f 100644 --- a/tests/exceptions-tests.ark +++ b/tests/exceptions-tests.ark @@ -1,26 +1,12 @@ -(import "tests-tools.ark") +(import std.Exceptions) +(import std.Testing) -(import "Exceptions.ark") - -(let exceptions-tests (fun () { - (mut tests 0) - (let start-time (time)) - - (let invert (fun (x) { - (if (= x 0) - (throw "cannot divide by zero") - (return (/ 1 x)))})) +(let invert (fun (x) + (if (= x 0) + (throw "cannot divide by zero") + (return (/ 1 x))))) +(test:suite exceptions { (try (invert 0) - (fun (inverted) (assert-val false "Exception test" tests)) - (fun (err) (set tests (assert-eq err "cannot divide by zero" "Exception test" tests)))) - - (try (invert 2) - (fun (inverted) (set tests (assert-eq inverted 0.5 "Exception test" tests))) - (fun (err) (assert-val false "Exception test" tests))) - - (recap "Exceptions tests passed" tests (- (time) start-time)) - - tests })) - -(let passed-exceptions (exceptions-tests)) \ No newline at end of file + (fun (inverted) (test:expect false)) + (fun (err) (test:expect (= err "cannot divide by zero"))))}) diff --git a/tests/functional-tests.ark b/tests/functional-tests.ark index ac48359..1294109 100644 --- a/tests/functional-tests.ark +++ b/tests/functional-tests.ark @@ -1,23 +1,13 @@ -(import "tests-tools.ark") +(import std.Functional) +(import std.Testing) -(import "Functional.ark") +(let foo (fun (x) (+ x 3))) +(let egg (fun (y) (* y 2))) +(let bar (fun (x y) (- x y))) -(let functional-tests (fun () { - (mut tests 0) - (let start-time (time)) - - (let foo (fun (x) (+ x 3))) - (let egg (fun (y) (* y 2))) - (let bar (fun (x y) (- x y))) - - (set tests (assert-eq ((compose foo egg) 5) (foo (egg 5)) "compose" tests)) - (set tests (assert-eq ((compose egg egg) 5) (egg (egg 5)) "compose" tests)) +(test:suite functional { + (test:eq ((compose foo egg) 5) (foo (egg 5))) + (test:eq ((compose egg egg) 5) (egg (egg 5))) # no need to test left and right because they were already tested by the exceptions tests (throw, return) - (set tests (assert-eq ((flip bar 5) 6) (bar 6 5) "flip" tests)) - (set tests (assert-eq ((flip bar 6) 5) (bar 5 6) "flip" tests)) - - (recap "Functional tests passed" tests (- (time) start-time)) - - tests })) - -(let passed-functional (functional-tests)) \ No newline at end of file + (test:eq ((flip bar 5) 6) (bar 6 5)) + (test:eq ((flip bar 6) 5) (bar 5 6))}) diff --git a/tests/lazy-tests.ark b/tests/lazy-tests.ark index dd4a154..361addd 100644 --- a/tests/lazy-tests.ark +++ b/tests/lazy-tests.ark @@ -1,24 +1,15 @@ -(import "tests-tools.ark") +(import std.Lazy) +(import std.Testing) -(import "Lazy.ark") - -(let lazy-tests (fun () { - (mut tests 0) - (let start-time (time)) - - (let calculate_the_sun_weight (fun () (begin (sys:sleep 50) 42))) - (let memo (lazy:eval calculate_the_sun_weight)) +(let calculate_the_sun_weight (fun () (begin (sys:sleep 50) 42))) +(let memo (lazy:eval calculate_the_sun_weight)) +(test:suite lazy { (mut timer-0 (time)) - (set tests (assert-eq (memo) 42 "memoize the sun weight" tests)) - (set tests (assert-gt (- (time) timer-0) 0.05 "lazy:eval ran the function for the first time" tests)) + (test:eq 42 (memo)) + # test execution time, should be long because the function wasn't memoized yet + (test:expect (> (- (time) timer-0) 0.050)) (set timer-0 (time)) - (set tests (assert-eq (memo) 42 "the memoized value hasn't changed" tests)) - (set tests (assert-lt (- (time) timer-0) 0.005 "lazy:eval returned the memoized value" tests)) - - (recap "Lazy tests passed" tests (- (time) start-time)) - - tests })) - -(let passed-lazy (lazy-tests)) \ No newline at end of file + (test:eq 42 (memo)) + (test:expect (< (- (time) timer-0) 0.050))}) diff --git a/tests/list-tests.ark b/tests/list-tests.ark index 846c89d..3856661 100644 --- a/tests/list-tests.ark +++ b/tests/list-tests.ark @@ -1,82 +1,72 @@ -(import "tests-tools.ark") +(import std.List) +(import std.Math :even) +(import std.Testing) -(import "List.ark") -(import "Math.ark") # for math:even - -(let list-tests (fun () { - (mut tests 0) - (let start-time (time)) - - (let a [1 2 3]) - (let b [4 5 6]) - (let zipped [[1 5] [2 6] [3 7] [4 8]]) +(let a [1 2 3]) +(let b [4 5 6]) +(let zipped [[1 5] [2 6] [3 7] [4 8]]) +(test:suite list { (list:forEach a (fun (e) { # just assert we have something, basically it's just a while + @ - (set tests (assert-neq e nil "forEach" tests))})) - - (set tests (assert-eq (list:product b) (* 4 5 6) "product" tests)) - (set tests (assert-eq (list:product []) 1 "product" tests)) - - (set tests (assert-eq (list:sum b) (+ 4 5 6) "sum" tests)) - (set tests (assert-eq (list:sum []) 0 "sum" tests)) - - (set tests (assert-eq (list:drop a 0) [1 2 3] "drop" tests)) - (set tests (assert-eq (list:drop a 1) [2 3] "drop" tests)) - (set tests (assert-eq (list:drop a 2) [3] "drop" tests)) + (test:neq e nil)})) - (set tests (assert-eq (list:dropWhile a (fun (c) (< c 0))) [1 2 3] "dropWhile" tests)) - (set tests (assert-eq (list:dropWhile a (fun (c) (< c 2))) [2 3] "dropWhile" tests)) - (set tests (assert-eq (list:dropWhile a (fun (c) (< c 5))) [] "dropWhile" tests)) + (test:eq (list:product b) (* 4 5 6)) + (test:eq (list:product []) 1) - (set tests (assert-eq (list:filter a math:even) [2] "filter" tests)) - (set tests (assert-eq (list:filter a (fun (e) (> e 100))) [] "filter" tests)) - (set tests (assert-eq (list:filter [] (fun (e) (> e 100))) [] "filter" tests)) + (test:eq (list:sum b) (+ 4 5 6)) + (test:eq (list:sum []) 0) - (set tests (assert-eq (list:map b (fun (e) (* e e))) [16 25 36] "map" tests)) - (set tests (assert-eq (list:map [] (fun (e) (* e e))) [] "map" tests)) + (test:eq (list:drop a 0) [1 2 3]) + (test:eq (list:drop a 1) [2 3]) + (test:eq (list:drop a 2) [3]) - (set tests (assert-eq (list:reduce a (fun (x y) (- x y))) -4 "reduce" tests)) + (test:eq (list:dropWhile a (fun (c) (< c 0))) [1 2 3]) + (test:eq (list:dropWhile a (fun (c) (< c 2))) [2 3]) + (test:eq (list:dropWhile a (fun (c) (< c 5))) []) - (set tests (assert-eq (list:flatten []) [] "flatten" tests)) - (set tests (assert-eq (list:flatten [[]]) [] "flatten" tests)) - (set tests (assert-eq (list:flatten [[1]]) [1] "flatten" tests)) - (set tests (assert-eq (list:flatten zipped) [1 5 2 6 3 7 4 8] "flatten" tests)) + (test:eq (list:filter a math:even) [2]) + (test:eq (list:filter a (fun (e) (> e 100))) []) + (test:eq (list:filter [] (fun (e) (> e 100))) []) - (set tests (assert-eq (list:flatMap [] (fun (a) [a a])) [] "flatMap" tests)) - (set tests (assert-eq (list:flatMap a (fun (a) (* 2 a))) [2 4 6] "flatMap" tests)) - (set tests (assert-eq (list:flatMap a (fun (a) [a a])) [1 1 2 2 3 3] "flatMap" tests)) + (test:eq (list:map b (fun (e) (* e e))) [16 25 36]) + (test:eq (list:map [] (fun (e) (* e e))) []) - (set tests (assert-eq (list:take a 1) [1] "take" tests)) - (set tests (assert-eq (list:take a 100) a "take" tests)) + (test:eq (list:reduce a (fun (x y) (- x y))) -4) - (set tests (assert-eq (list:takeWhile a (fun (c) (< c 0))) [] "takeWhile" tests)) - (set tests (assert-eq (list:takeWhile a (fun (c) (< c 2))) [1] "takeWhile" tests)) - (set tests (assert-eq (list:takeWhile a (fun (c) (< c 3))) [1 2] "takeWhile" tests)) - (set tests (assert-eq (list:takeWhile a (fun (c) (< c 5))) [1 2 3] "takeWhile" tests)) + (test:eq (list:flatten []) []) + (test:eq (list:flatten [[]]) []) + (test:eq (list:flatten [[1]]) [1]) + (test:eq (list:flatten zipped) [1 5 2 6 3 7 4 8]) - (set tests (assert-eq (list:unzip zipped) [[1 2 3 4] [5 6 7 8]] "unzip" tests)) - (set tests (assert-eq (list:unzip []) [[] []] "unzip" tests)) + (test:eq (list:flatMap [] (fun (a) [a a])) []) + (test:eq (list:flatMap a (fun (a) (* 2 a))) [2 4 6]) + (test:eq (list:flatMap a (fun (a) [a a])) [1 1 2 2 3 3]) - (set tests (assert-eq (list:zip a b) [[1 4] [2 5] [3 6]] "zip" tests)) - (set tests (assert-eq (list:zip [] []) [] "zip" tests)) + (test:eq (list:take a 1) [1]) + (test:eq (list:take a 100) a) - (set tests (assert-eq (list:foldLeft [] 0 (fun (x y) (+ x y))) 0 "foldLeft" tests)) - (set tests (assert-eq (list:foldLeft ["1" "2" "3"] "" (fun (x y) (+ x y))) "123" "foldLeft" tests)) - (set tests (assert-eq (list:foldLeft a 0 (fun (x y) (+ x y))) 6 "foldLeft" tests)) + (test:eq (list:takeWhile a (fun (c) (< c 0))) []) + (test:eq (list:takeWhile a (fun (c) (< c 2))) [1]) + (test:eq (list:takeWhile a (fun (c) (< c 3))) [1 2]) + (test:eq (list:takeWhile a (fun (c) (< c 5))) [1 2 3]) - (set tests (assert-eq a [1 2 3] "unmodified list" tests)) - (set tests (assert-eq b [4 5 6] "unmodified list" tests)) + (test:eq (list:unzip zipped) [[1 2 3 4] [5 6 7 8]]) + (test:eq (list:unzip []) [[] []]) - (set tests (assert-eq (list:forAll a (fun (e) (< e 4))) true "list:forAll" tests)) - (set tests (assert-eq (list:forAll a (fun (e) (< e 2))) false "list:forAll" tests)) - (set tests (assert-eq (list:forAll [] (fun (e) (= e 2))) true "list:forAll" tests)) - (set tests (assert-eq (list:any a (fun (e) (< e 2))) true "list:any" tests)) - (set tests (assert-eq (list:any a (fun (e) (> e 8))) false "list:any" tests)) - (set tests (assert-eq (list:any [] (fun (e) (= e 8))) false "list:any" tests)) + (test:eq (list:zip a b) [[1 4] [2 5] [3 6]]) + (test:eq (list:zip [] []) []) - (recap "List tests passed" tests (- (time) start-time)) + (test:eq (list:foldLeft [] 0 (fun (x y) (+ x y))) 0) + (test:eq (list:foldLeft ["1" "2" "3"] "" (fun (x y) (+ x y))) "123") + (test:eq (list:foldLeft a 0 (fun (x y) (+ x y))) 6) - tests })) + (test:eq a [1 2 3]) + (test:eq b [4 5 6]) -(let passed-list (list-tests)) \ No newline at end of file + (test:expect (list:forAll a (fun (e) (< e 4)))) + (test:expect (not (list:forAll a (fun (e) (< e 2))))) + (test:expect (list:forAll [] (fun (e) (= e 2)))) + (test:expect (list:any a (fun (e) (< e 2)))) + (test:expect (not (list:any a (fun (e) (> e 8))))) + (test:expect (not (list:any [] (fun (e) (= e 8)))))}) diff --git a/tests/macros-tests.ark b/tests/macros-tests.ark index 7873e02..6e641af 100644 --- a/tests/macros-tests.ark +++ b/tests/macros-tests.ark @@ -1,31 +1,21 @@ -(import "tests-tools.ark") - -(import "Macros.ark") - -(let macros-tests (fun () { - (mut tests 0) - (let start-time (time)) - - (let f1 (fun (data) - (+ data "-f1"))) - (let f2 (fun (data) - (+ data "-f2"))) - (let f3 (fun (data) - (+ data "-f3"))) - - (set tests (assert-eq (-> "f0" f1) "f0-f1" "Threading macro threaded the given functions" tests)) - (set tests (assert-eq (-> "f0" f1 f2 f3) "f0-f1-f2-f3" "Threading macro threaded the given functions" tests)) - - (let test_func (fun (a b c) (* a b c))) - (let test_func1 (partial test_func 1)) - (let test_func2 (partial test_func1 2)) - - (set tests (assert-eq (test_func1 2 3) 6 "Partial macro created a partial callable function" tests)) - (set tests (assert-eq (argcount test_func1) 2 "Argcount of the partial function should be 2" tests)) - (set tests (assert-eq (argcount test_func2) 1 "Argcount of the partial function should be 1" tests)) - - (recap "Macros tests passed" tests (- (time) start-time)) - - tests })) - -(let passed-macros (macros-tests)) \ No newline at end of file +(import std.Macros) +(import std.Testing) + +(let f1 (fun (data) + (+ data "-f1"))) +(let f2 (fun (data) + (+ data "-f2"))) +(let f3 (fun (data) + (+ data "-f3"))) + +(let test_func (fun (a b c) (* a b c))) +(let test_func1 (partial test_func 1)) +(let test_func2 (partial test_func1 2)) + +(test:suite macros { + (test:eq (-> "f0" f1) "f0-f1") + (test:eq (-> "f0" f1 f2 f3) "f0-f1-f2-f3") + + (test:eq (test_func1 2 3) 6) + (test:eq (argcount test_func1) 2) + (test:eq (argcount test_func2) 1)}) \ No newline at end of file diff --git a/tests/math-tests.ark b/tests/math-tests.ark index 22b1d11..adce7dc 100644 --- a/tests/math-tests.ark +++ b/tests/math-tests.ark @@ -1,40 +1,37 @@ -(import "tests-tools.ark") +(import std.Math) +(import std.Testing) + +(test:suite math { + (test:eq (math:abs -1) 1) + (test:eq (math:abs 1) 1) + (test:expect (math:even 2)) + (test:expect (math:even -2)) + (test:expect (math:odd 1)) + (test:expect (math:odd -1)) + (test:eq (math:min 1 2) 1) + (test:eq (math:min 1 -2) -2) + (test:eq (math:min 0.5 0.2) 0.2) + (test:eq (math:max 1 2) 2) + (test:eq (math:max 1 -2) 1) + (test:eq (math:max 0.5 0.2) 0.5) + (test:eq (math:pow 2 2) 4) + (test:eq (math:pow 4 0.5) 2) -(import "Math.ark") - -(let math-tests (fun () { - (mut tests 0) - (let start-time (time)) - - (set tests (assert-eq (math:abs -1) 1 "math:abs" tests)) - (set tests (assert-eq (math:abs 1) 1 "math:abs" tests)) - (set tests (assert-val (math:even 2) "math:even" tests)) - (set tests (assert-val (math:even -2) "math:even" tests)) - (set tests (assert-val (math:odd 1) "math:odd" tests)) - (set tests (assert-val (math:odd -1) "math:odd" tests)) - (set tests (assert-eq (math:min 1 2) 1 "math:min" tests)) - (set tests (assert-eq (math:min 1 -2) -2 "math:min" tests)) - (set tests (assert-eq (math:min 0.5 0.2) 0.2 "math:min" tests)) - (set tests (assert-eq (math:max 1 2) 2 "math:max" tests)) - (set tests (assert-eq (math:max 1 -2) 1 "math:max" tests)) - (set tests (assert-eq (math:max 0.5 0.2) 0.5 "math:max" tests)) - (set tests (assert-eq (math:pow 2 2) 4 "math:pow" tests)) - (set tests (assert-eq (math:pow 4 0.5) 2 "math:pow" tests)) # small trick with toNumber because we have number's approximation because of the underlying double - (set tests (assert-eq (math:fibo 31) (toNumber "1346269") "math:fibo" tests)) - # small trick with toNumber because we have number's approximation because of the underlying double - (set tests (assert-eq (math:fibo 32) (toNumber "2178309") "math:fibo" tests)) - (set tests (assert-eq (math:divs 6) [1 2 3 6] "math:divs" tests)) - (set tests (assert-eq (math:divs 2) [1 2] "math:divs" tests)) - (set tests (assert-eq (math:divs 931) [1 7 19 49 133 931] "math:divs" tests)) - (set tests (assert-eq (math:log 27 3) 3 "math:log" tests)) - (set tests (assert-eq (math:log 1953125 5) 9 "math:log" tests)) - (set tests (assert-eq (math:log2 128) 7 "math:log2" tests)) - (set tests (assert-eq (math:log2 2048) 11 "math:log2" tests)) - (set tests (assert-eq (math:log10 1000) 3 "math:log10" tests)) - (set tests (assert-eq (math:floordiv 14 6) 2 "math:floordiv" tests)) - (set tests (assert-eq (math:floordiv 14 14) 1 "math:floordiv" tests)) - (set tests (assert-eq (math:floordiv 14 15) 0 "math:floordiv" tests)) + (test:eq (math:fibo 31) (toNumber "1346269")) + (test:eq (math:fibo 32) (toNumber "2178309")) + + (test:eq (math:divs 6) [1 2 3 6]) + (test:eq (math:divs 2) [1 2]) + (test:eq (math:divs 931) [1 7 19 49 133 931]) + (test:eq (math:log 27 3) 3) + (test:eq (math:log 1953125 5) 9) + (test:eq (math:log2 128) 7) + (test:eq (math:log2 2048) 11) + (test:eq (math:log10 1000) 3) + (test:eq (math:floordiv 14 6) 2) + (test:eq (math:floordiv 14 14) 1) + (test:eq (math:floordiv 14 15) 0) (let c0 (math:complex 1 2)) (let c1 (math:complex 0 -1)) @@ -43,54 +40,47 @@ (let c4 (math:complex 4 12)) (mut c_add (math:complex-add c0 c1)) - (set tests (assert-eq c_add.real 1 "math:complex-add" tests)) - (set tests (assert-eq c_add.imag 1 "math:complex-add" tests)) + (test:eq c_add.real 1) + (test:eq c_add.imag 1) (set c_add (math:complex-add c2 c3)) - (set tests (assert-eq c_add.real -110 "math:complex-add" tests)) - (set tests (assert-eq c_add.imag -65 "math:complex-add" tests)) + (test:eq c_add.real -110) + (test:eq c_add.imag -65) (mut c_sub (math:complex-sub c0 c1)) - (set tests (assert-eq c_sub.real 1 "math:complex-sub" tests)) - (set tests (assert-eq c_sub.imag 3 "math:complex-sub" tests)) + (test:eq c_sub.real 1) + (test:eq c_sub.imag 3) (set c_sub (math:complex-sub c2 c3)) - (set tests (assert-eq c_sub.real 24 "math:complex-sub" tests)) - (set tests (assert-eq c_sub.imag 113 "math:complex-sub" tests)) + (test:eq c_sub.real 24) + (test:eq c_sub.imag 113) (mut c_mul (math:complex-mul c0 c1)) - (set tests (assert-eq c_mul.real 2 "math:complex-mul" tests)) - (set tests (assert-eq c_mul.imag -1 "math:complex-mul" tests)) + (test:eq c_mul.real 2) + (test:eq c_mul.imag -1) (set c_mul (math:complex-mul c2 c3)) - (set tests (assert-eq c_mul.real 5017 "math:complex-mul" tests)) - (set tests (assert-eq c_mul.imag 2219 "math:complex-mul" tests)) + (test:eq c_mul.real 5017) + (test:eq c_mul.imag 2219) (mut c_div (math:complex-div c0 c1)) - (set tests (assert-eq c_div.real -2 "math:complex-div" tests)) - (set tests (assert-eq c_div.imag 1 "math:complex-div" tests)) + (test:eq c_div.real -2) + (test:eq c_div.imag 1) (set c_div (math:complex-div c4 c0)) - (set tests (assert-eq c_div.real 5.6 "math:complex-div" tests)) - (set tests (assert-eq c_div.imag 0.8 "math:complex-div" tests)) + (test:eq c_div.real 5.6) + (test:eq c_div.imag 0.8) (mut c_conj (math:complex-conjugate c0)) - (set tests (assert-eq c_conj.real 1 "math:complex-conjugate" tests)) - (set tests (assert-eq c_conj.imag -2 "math:complex-conjugate" tests)) + (test:eq c_conj.real 1) + (test:eq c_conj.imag -2) (set c_conj (math:complex-conjugate c3)) - (set tests (assert-eq c_conj.real -67 "math:complex-conjugate" tests)) - (set tests (assert-eq c_conj.imag 89 "math:complex-conjugate" tests)) - - (set tests (assert-lt (math:abs (- (math:complex-module c0) 2.236067977499789)) 0.0001 "math:complex-module" tests)) - (set tests (assert-lt (math:abs (- (math:complex-module c1) 1)) 0.0001 "math:complex-module" tests)) - (set tests (assert-lt (math:abs (- (math:complex-module c2) 49.244289008980523)) 0.0001 "math:complex-module" tests)) - # FIXME computing c3 is crashing the vm, I suspect an integer/double overflow here - # (set tests (assert-lt (math:abs (- (math:complex-module c3) 111.400179533068976)) 0.0001 "math:complex-module" tests)) - # (set tests (assert-lt (math:abs (- (math:complex-module c4) 12.649110640673517)) 0.0001 "math:complex-module" tests)) - - (recap "Math tests passed" tests (- (time) start-time)) - - tests })) - -(let passed-math (math-tests)) \ No newline at end of file + (test:eq c_conj.real -67) + (test:eq c_conj.imag 89) + + (test:expect (< (math:abs (- (math:complex-module c0) 2.236067977499789)) 0.0001)) + (test:expect (< (math:abs (- (math:complex-module c1) 1)) 0.0001)) + (test:expect (< (math:abs (- (math:complex-module c2) 49.244289008980523)) 0.0001)) + (test:expect (< (math:abs (- (math:complex-module c3) 111.400179533068976)) 0.0001)) + (test:expect (< (math:abs (- (math:complex-module c4) 12.649110640673517)) 0.0001))}) diff --git a/tests/range-tests.ark b/tests/range-tests.ark index 034d030..c2b2d6b 100644 --- a/tests/range-tests.ark +++ b/tests/range-tests.ark @@ -1,37 +1,27 @@ -(import "tests-tools.ark") - -(import "Range.ark") -(import "Math.ark") # for math:even - -(let range-tests (fun () { - (mut tests 0) - (let start-time (time)) +(import std.Range) +(import std.Math :even) +(import std.Testing) +(test:suite range { (let r (range 0 10)) (mut i 0) (while (< i 10) { - (set tests (assert-eq i (r) "range" tests)) + (test:eq i (r)) (set i (+ 1 i))}) - (set tests (assert-eq r.i 10 "range" tests)) - (set tests (assert-eq (r) nil "range" tests)) + (test:eq r.i 10) + (test:eq (r) nil) (r.reset) - (set tests (assert-eq r.i 0 "range reset" tests)) - (set tests (assert-eq (r.asList) [0 1 2 3 4 5 6 7 8 9] "range asList" tests)) + (test:eq r.i 0) + (test:eq (r.asList) [0 1 2 3 4 5 6 7 8 9]) (range:forEach r (fun (e) - (set tests (assert-neq e nil "range forEach" tests)))) + (test:neq e nil))) (let filtered (range:filter r math:even)) - (set tests (assert-eq filtered [0 2 4 6 8] "range filter" tests)) + (test:eq filtered [0 2 4 6 8]) (let mapped (range:map r (fun (e) (* e e)))) - (set tests (assert-eq mapped [0 1 4 9 16 25 36 49 64 81] "range map" tests)) + (test:eq mapped [0 1 4 9 16 25 36 49 64 81]) (let reduced (range:reduce r (fun (a b) (+ a b)))) - (set tests (assert-eq reduced 45 "range reduced" tests)) - - (recap "Range tests passed" tests (- (time) start-time)) - - tests })) - -(let passed-range (range-tests)) \ No newline at end of file + (test:eq reduced 45)}) diff --git a/tests/string-tests.ark b/tests/string-tests.ark index 18a8fae..cb56736 100644 --- a/tests/string-tests.ark +++ b/tests/string-tests.ark @@ -1,41 +1,32 @@ -(import "tests-tools.ark") - -(import "String.ark") - -(let string-tests (fun () { - (mut tests 0) - (let start-time (time)) - - (set tests (assert-eq "abcdefghijklmnopqrstuvwxyz" (str:toLower "ABCDEFGHIJKLMNOPQRSTUVWXYZ") "string lower" tests)) - (set tests (assert-eq "abcdefghijklmnopqrstuvwxyz" (str:toLower "abcdefghijklmnopqrstuvwxyz") "string lower" tests)) - (set tests (assert-eq "ABCDEFGHIJKLMNOPQRSTUVWXYZ" (str:toUpper "abcdefghijklmnopqrstuvwxyz") "string upper" tests)) - (set tests (assert-eq "ABCDEFGHIJKLMNOPQRSTUVWXYZ" (str:toUpper "ABCDEFGHIJKLMNOPQRSTUVWXYZ") "string upper" tests)) - - (set tests (assert-eq "hello world" (str:reverse "dlrow olleh") "string reverse" tests)) - (set tests (assert-eq "" (str:reverse "") "string reverse" tests)) - (set tests (assert-eq "a" (str:reverse "a") "string reverse" tests)) - - (set tests (assert-eq "hello" (str:slice "hello world" 0 5) "string slice" tests)) - (set tests (assert-eq "hello world" (str:slice "hello world" 0 100) "string slice" tests)) - (set tests (assert-eq "h" (str:slice "hello world" 0 1) "string slice" tests)) - (set tests (assert-eq "ello" (str:slice "hello world" 1 4) "string slice" tests)) - - (set tests (assert-eq ["a" "bc" "def"] (str:split "a,bc,def" ",") "string split" tests)) - (set tests (assert-eq ["a" "bc" "def"] (str:split "a-;-bc-;-def" "-;-") "string split" tests)) - (set tests (assert-eq ["abcdef"] (str:split "abcdef" ";;;;") "string split" tests)) - (set tests (assert-eq ["a"] (str:split "a" ",") "string split" tests)) - (set tests (assert-eq [] (str:split "" ",") "string split" tests)) - - (set tests (assert-eq "hello world" (str:replace "hello world" "coucou" "not") "string replace" tests)) - (set tests (assert-eq "not world" (str:replace "hello world" "hello" "not") "string replace" tests)) - (set tests (assert-eq "not not " (str:replace "hello hello " "hello" "not") "string replace" tests)) - - (set tests (assert-eq "hello;3.14;true;world" (str:join ["hello" 3.14 true "world"] ";") "string join" tests)) - (set tests (assert-eq "hello" (str:join ["hello"] ";") "string join" tests)) - (set tests (assert-eq "" (str:join [] ";;") "string join" tests)) - - (recap "String tests passed" tests (- (time) start-time)) - - tests })) - -(let passed-string (string-tests)) \ No newline at end of file +(import std.String) +(import std.Testing) + +(test:suite string { + (test:eq "abcdefghijklmnopqrstuvwxyz" (str:toLower "ABCDEFGHIJKLMNOPQRSTUVWXYZ")) + (test:eq "abcdefghijklmnopqrstuvwxyz" (str:toLower "abcdefghijklmnopqrstuvwxyz")) + (test:eq "ABCDEFGHIJKLMNOPQRSTUVWXYZ" (str:toUpper "abcdefghijklmnopqrstuvwxyz")) + (test:eq "ABCDEFGHIJKLMNOPQRSTUVWXYZ" (str:toUpper "ABCDEFGHIJKLMNOPQRSTUVWXYZ")) + + (test:eq "hello world" (str:reverse "dlrow olleh")) + (test:eq "" (str:reverse "")) + (test:eq "a" (str:reverse "a")) + + (test:eq "hello" (str:slice "hello world" 0 5)) + (test:eq "hello world" (str:slice "hello world" 0 100)) + (test:eq "h" (str:slice "hello world" 0 1)) + (test:eq "ello" (str:slice "hello world" 1 4)) + + (test:eq ["a" "bc" "def"] (str:split "a,bc,def" ",")) + (test:eq ["a" "bc" "def"] (str:split "a-;-bc-;-def" "-;-")) + (test:eq ["abcdef"] (str:split "abcdef" ";;;;")) + (test:eq ["a"] (str:split "a" ",")) + (test:eq [] (str:split "" ",")) + + #(test:eq "hello world" (str:replace "hello world" "coucou" "not")) + #(test:eq "not world" (str:replace "hello world" "hello" "not")) + (test:eq "not not " (str:replace "hello hello " "hello" "not")) + (test:eq "hello worldworldABC" (str:replace "hello worldABC" "ABC" "worldABC")) + + (test:eq "hello;3.14;true;world" (str:join ["hello" 3.14 true "world"] ";")) + (test:eq "hello" (str:join ["hello"] ";")) + (test:eq "" (str:join [] ";;"))}) \ No newline at end of file diff --git a/tests/switch-tests.ark b/tests/switch-tests.ark index ce8afc9..fee06a5 100644 --- a/tests/switch-tests.ark +++ b/tests/switch-tests.ark @@ -1,28 +1,12 @@ -(import "tests-tools.ark") - -(import "Switch.ark") - -(let switch-tests (fun () { - (mut tests 0) - (let start-time (time)) +(import std.Switch) +(import std.Testing) +(test:suite switch { (switch 12 [ - [0 '(assert-val false "switch 12" tests)] - [-1 '(assert-val false "switch 12" tests)] - [nil '(assert-val false "switch 12" tests)] - ["12" '(assert-val false "switch 12" tests)] - [[12] '(assert-val false "switch 12" tests)] - [12 '(set tests (assert-val true "switch 12" tests))] - [true '(assert-val false "switch 12" tests)]]) - - # FIXME: this is crashing the GCC8 and GCC11 builds - # (switch 0 [ - # [nil '(assert-val false "switch 0" tests)] - # ]) - # (set tests (assert-val true "switch 0" tests)) - - (recap "Switch tests passed" tests (- (time) start-time)) - - tests })) - -(let passed-switch (switch-tests)) \ No newline at end of file + [0 (fun () (test:expect false))] + [-1 (fun () (test:expect false))] + [nil (fun () (test:expect false))] + ["12" (fun () (test:expect false))] + [[12] (fun () (test:expect false))] + [12 (fun () (test:expect true))] + [true (fun () (test:expect false))]])}) diff --git a/tests/tests-tools.ark b/tests/tests-tools.ark deleted file mode 100644 index eccc3f6..0000000 --- a/tests/tests-tools.ark +++ /dev/null @@ -1,50 +0,0 @@ -(import "console.arkm") - -(let assert-eq (fun (val1 val2 message tests) { - (assert (= val1 val2) (str:format "%% (%%) - %% SHOULD BE EQUAL TO %%" message tests val1 val2)) - (+ 1 tests)})) - -(let assert-neq (fun (val1 val2 message tests) { - (assert (!= val1 val2) (str:format "%% (%%) - %% SHOULD BE NOT EQUAL TO %%" message tests val1 val2)) - (+ 1 tests)})) - -(let assert-gt (fun (val1 val2 message tests) { - (assert (> val1 val2) (str:format "%% (%%) - %% SHOULD BE GREATER THAN %%" message tests val1 val2)) - (+ 1 tests)})) - -(let assert-ge (fun (val1 val2 message tests) { - (assert (>= val1 val2) (str:format "%% (%%) - %% SHOULD BE GREATER OR EQUAL TO %%" message tests val1 val2)) - (+ 1 tests)})) - -(let assert-lt (fun (val1 val2 message tests) { - (assert (< val1 val2) (str:format "%% (%%) - %% SHOULD BE LESSER THAN %%" message tests val1 val2)) - (+ 1 tests)})) - -(let assert-le (fun (val1 val2 message tests) { - (assert (<= val1 val2) (str:format "%% (%%) - %% SHOULD BE LESSER OR EQUAL TO %%" message tests val1 val2)) - (+ 1 tests)})) - -(let assert-val (fun (val0 message tests) { - (assert val0 (str:format "%% (%%) - %% SHOULD BE TRUTHY" message tests val0)) - (+ 1 tests)})) - -(let recap (fun (test-name tests time_) { - (console:color "yellow") - (puts " " test-name " ") - (if (<= (len test-name) 20) - (puts "\t\t") - (puts "\t")) - - (console:color "reset") - (puts "(") - - (console:color "blue") - (puts tests) - - (console:color "reset") - (puts ")\tin ") - - (console:color "green") - (puts (* 1000 time_) "ms\n") - - (console:color "reset")})) \ No newline at end of file