Here is a small test framework I made to runs the testcases inside Emacs on the Clojure Repl.
Just include clojure.pprint
in the namespace and paste the rest of the code under your -main
function.
For each new game you have to copy and paste the urls for the input and output files from the problem description. Then you can use (run-test <testcase>)
to compare your output to the expected output.
This example is for the “Bender - Algorithmic Complexity” game.
(ns Solution (:gen-class) (:use [clojure.pprint :as pp :only (cl-format pprint)])
(def ^:dynamic *testcases*
'(("O(1)"
"https://code.codingame.com/servlet/fileservlet?id=549349084930"
"https://code.codingame.com/servlet/fileservlet?id=549350237669")
("O(logn)"
"https://code.codingame.com/servlet/fileservlet?id=549385510196"
"https://code.codingame.com/servlet/fileservlet?id=549391419271")
("O(n)"
"https://code.codingame.com/servlet/fileservlet?id=549425470904"
"https://code.codingame.com/servlet/fileservlet?id=549439028979")
("O(nlogn)"
"https://code.codingame.com/servlet/fileservlet?id=549466416338"
"https://code.codingame.com/servlet/fileservlet?id=549476004749")
("O(n^2)"
"https://code.codingame.com/servlet/fileservlet?id=549500048576"
"https://code.codingame.com/servlet/fileservlet?id=549519236043")
("O(n^2logn)"
"https://code.codingame.com/servlet/fileservlet?id=549544076693"
"https://code.codingame.com/servlet/fileservlet?id=549559605882")
("O(n^3)"
"https://code.codingame.com/servlet/fileservlet?id=549588533737"
"https://code.codingame.com/servlet/fileservlet?id=549596182441")
("2^n"
"https://code.codingame.com/servlet/fileservlet?id=549629594048"
"https://code.codingame.com/servlet/fileservlet?id=549633349793")))
(defmacro with-testcase
"Take a TESTCASE in the form '(NAME INPUT-URL OUTPUT-URL) and bind *IN* to a
reader that reads from INPUT-URL."
[testcase & body]
`(let [[_ data-url# _] ~testcase]
(with-open [rdr# (clojure.lang.LineNumberingPushbackReader.
(java.io.InputStreamReader.
(.openStream
(java.net.URL.
data-url#))))]
(binding [*in* rdr#]
(do ~@body)))))
;; (with-testcase (first *testcases*) (list (read) (read-line) (read-line)))
;; => (100 "" "10 200000")
(defn sample
"Take N elements from SEQ. If SEQ is longer insert a placeholder at the end."
[n seq]
(if (string? seq)
(cl-format nil "~a~a" (subs seq 0 (min n (.length seq))) (if (> (.length seq) n) "[..]" ""))
(if (coll? seq)
(if (> (count seq) n)
(concat (take n seq) (list (symbol (cl-format nil "..~a" (- (count seq) n)))))
(take n seq))
nil)))
;; (sample 3 (range 10))
;; => (0 1 2 ..7)
;; (sample 3 "asdfgh")
;; => "asd[..]"
(defn run-test
"Take a TESTCASE in the form '(NAME INPUT-URL OUTPUT-URL) and run -MAIN while
taking input from INPUT-URL and comparing the result to OUTPUT-URL. Print a
summary to *OUT* and return either TRUE or FALSE."
[testcase]
(cl-format *out* "----- Testcase: ~a -----~%" (first testcase))
(let [result-expected (slurp (nth testcase 2))]
(with-testcase testcase
(let [result-actual (time (with-out-str (-main)))
passed (= result-actual result-expected)]
(cl-format *out*
" actual: ~s~%expected: ~s~%~a~%"
(sample 80 result-actual)
(sample 80 result-expected)
(if passed "ok" "error"))
passed))))
;; (run-test (first *testcases*))
;; => ----- Testcase: O(1) -----
;; => "Elapsed time: 0.98633 msecs"
;; => actual: "O(1)\n"
;; => expected: "O(1)\n"
;; => ok
;; => true
(defn run-tests []
(map run-test *testcases*))