Fork me on GitHub

#orgmode metal(with live example featuring Clojure in org-babel)

❤️ 2

> I have never used org for managing TODOs, calendaring, or any “productivity” use cases (time tracking, GTD etc.), which it has become popular for. Nor, as is also popular these days, is it my “second brain”. (Or maybe it is because my ~/org directory is a total disaster zone. I just disorganise and use Emacs to search through the files.). This made me laugh out loud 😄 ❤️


> I discovered it about a decade ago (circa 2013), right after I changed careers to “tech”, because all the gentlenerds at the little company used Emacs. Told ya. Not normal. (Although, surprisingly, lots of normies use it too. Hi friends!). What did you do before tech?


> Yes m’lorx, this way please typo - "m'lord"? (though m'lorx undoubtably sounds cool)


m'lorx is like cljx ... all-purpose. I couldn't come up with a better one :D

😄 2

> What did you do before tech? business / management stuff


what made you switch? Are you happy you did?


It's complicated :)


interesting things often are complicated 😄

🥲 1

Why not to put tests into source file right behind function you are testing?


And why test is not just a function with meta and context params?


@nicola The TL;DR is that test tooling doesn't generally expect tests to be in source files so default test runners don't always find such tests. The Expectations library docs talks about that in more detail:


They are functions, but without arguments :(


Would be an interesting exercise to count which runners do accept src and which do not. I'd healthily question whether most and everyone are accurate wording in that cljdoc :)


And an even more useful exercise would be to report flaws in runners and get them fixed - no real reason to get stuck in suboptimality


@U45T93RA6 that doc explains how to get the test runners to run tests in src - the point I'm making is that it's not the default behavior and it's not what any of the books or tutorials teach. I think co-located tests are fine and clojure.test inherently supports them (`with-test`) - modulo the caveats.


(and tests are "just functions with metadata")

☝️ 1

When I feel like a test belongs with the function in question (e.g. when it would also serve as a part of the documentation) and when it can be expressed as a sequence of arg vectors, I just put that sequence somewhere in the functions metadata and create a separate test that simply runs that function in the right context with all those arguments from the sequence, one by one.

👍 1

That's a neat approach -- I'll try to remember that!

🙂 1
Oliver George22:04:18

Can you post an example please


Sure, something like this:

;; In `/src`

(defn do-stuff
  "Does some stuff - usually adds two numbers together."
  {:test-data {[1 1]  2
               [1 2]  3
               [-1 1] 0}}
  [x y]
  (+ x y))

;; In `/test`
  (:require [clojure.test :refer :all]))

(deftest test-data-in-bar []
  (doseq [[sym var] (ns-publics ']
    (when-some [td (:test-data (meta var))]
      (doseq [[args expected] td]
        (let [result (apply @var args)]
          (is (= result expected) (pr-str (list sym args))))))))

👍 13

Hum... That's pretty neat

Martynas Maciulevičius06:04:13

In golang they like to do something similar (except they don't define it on the fn (but you could (although the compiler would complain about unused var))): (also wow, getting 8 upvotes is quite rare here 😄)


I'm surprised with that myself. :D My code above is just a lazy man's (and also happens to be more flexible because you're in full control and the implementation is just a few lines).


This alternative means cider-test-run-test (run test at <cursor>) or any equivalent feature won't work. also doseq and when-some are prone to false negatives here - one doesn't want tests to misteriously stop running

Martynas Maciulevičius10:04:32

If you'd have test boilerplate for each method then it would still work. Maybe it could be done via a macro. But in the case of a test-executing macro it wouldn't produce a testfile to run. Again, coming from golang world it could be done via a code generator... Where you could generate your test boilerplate file for this method when it has this metadata.


@U45T93RA6 Regarding the cider point - I think I know what you mean and I realized that I used defn instead of deftest - that's corrected now. Regarding doseq and when-some - I don't get it. Where would false negatives come from?


I meant something else regarding cider with the original pattern you can cider-test-run-test over a defn ^{:test ... , it's super handy as you remain focused in the sources > Where would false negatives come from? If you rename tests, or have typos in the :test-data name, etc the deftest would pass, but running zero assertions


Ah, well, you can easily define your own function that just runs over :test-data and put it under :test. That will actually solve your second point as well - that :test function can assert that there's some test data.


But I myself wouldn't consider a possible typo in :test-data to be a good argument against using something like :test-data. You can make typos anywhere that introduce false negatives, there's no generic guard against that.

Martynas Maciulevičius10:04:40

@U45T93RA6 If you want you could have a build step that validates that all your metadata of the functions has only specified keywords as keys. This way you'd know that you messed up.


@U45T93RA6 Actually you gave me an idea, so here's an improvement that should tick all the boxes. :D Two downsides though: • Tools that check for an explicit deftest in the source code (e.g. Cursive) won't see a test there • You'll have to include your sources in the list of resources that has to be checked by a test runner

(defn with-test-data [& data]
  (assert (even? (count data)))
  (fn []
    (let [f-under-test (peek clojure.test/*testing-vars*)]
      (doseq [[args expected] (partition 2 data)]
        (let [result (apply f-under-test args)]
          (is (= expected result) (pr-str (concat (list (.-sym f-under-test)) args))))))))

(defn do-stuff
  {:test (with-test-data [1 1] 2
                         [1 2] 3
                         [-1 1] 0
                         ;; Just to see how a failure looks.
                         [42 0] 7)}
  [x y]
  (+ x y))


The normal test meta takes too much real estate in the source file, that's why I upvoted this approach, I like the minimalism.

Martynas Maciulevičius15:04:31

@U2FRKM4TW It could also be done this way too (not sure if :pre can go before args).

(defn do-stuff
  (merge ;; This one can be something else
         {:pre [1 2 3]}
         (with-test [1 1] 2
                    [1 2] 3
                    [-1 1] 0
                    ;; Just to see how a failure looks.
                    [42 0] 7))
  [x y]
  (+ x y))