Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Same type for asserting occurrences of same value #25

Merged
merged 2 commits into from
May 6, 2024
Merged

Same type for asserting occurrences of same value #25

merged 2 commits into from
May 6, 2024

Conversation

snoe
Copy link
Contributor

@snoe snoe commented May 6, 2024

When you have an unknown value that needs to repeat in the expected assertion you don't have a lot of good options. You can let the result, and pull out as many values as you want to check but this quickly gets cumbersome, where the structure of actual needs to be declared twice, once to pull out the values to check and again in expected.

In this case, we want to assert, that <id1> and <id2> are the same across the actual value. We can do this with =?/same

(let [actual [{:id <id1> :ref [:field <id1>]}
              {:id <id2> :ref [:field <id2>]}]
      id1 (get-in actual [0 :id])
      id2 (get-in actual [1 :id])]
  (is (=? [{:id id1 :ref [:field id1]} {:id id2 :ref [:field id2] actual)))

(let [actual [{:id <id1> :ref [:field <id1>]}
              {:id <id2> :ref [:field <id2>]}]]
  (is (=? [{:id (=?/same :id1) :ref [:field (=?/same :id1)]}
           {:id (=?/same :id2) :ref [:field (=?/same :id2)]}]
           actual)))

When you have an unknown value that needs to repeat in the expected
assertion you don't have a lot of good options. You can let the result,
and pull out as many values as you want to check but this quickly gets
cumbersome, where the structure of actual needs to be declared twice,
once to pull out the values to check and again in expected.

In this case, we want to assert, that `<id1>` and `<id2> are the same
across the actual value. We can do this with `=?/same`

```
(let [actual [{:id <id1> :ref [:field <id1>]}
              {:id <id2> :ref [:field <id1>]}]
      id1 (get-in actual [0 :id])
      id2 (get-in actual [1 :id])]
  (is (=? [{:id id1 :ref [:field id1]} {:id id2 :ref [:field id2] actual)))

(let [actual [{:id <id1> :ref [:field <id1>]}
              {:id <id2> :ref [:field <id1>]}]]
  (is (=? [{:id (=?/same :id1) :ref [:field (=?/same :id1)]}
           {:id (=?/same :id2) :ref [:field (=?/same :id2)]}]
           actual)))
```
@snoe snoe requested a review from a team May 6, 2024 20:37
@snoe snoe self-assigned this May 6, 2024
@snoe snoe requested a review from camsaul as a code owner May 6, 2024 20:37
@dpsutton
Copy link
Contributor

dpsutton commented May 6, 2024

this looks awesome! Only thought, what about throwing the label into (deftype Same [k]) so that if there are multiple in a structure, we can say which label(s) had the inconsistency?

motivating:

approximately-equal-test=> (is (=? {:parent {:foo [(=?/same :a) (=?/same :a) (=?/same :b)]
                                             :bar (=?/same :a)
                                             :qux {:a {:b [[(=?/same :b)]]}}}}
                                   {:parent {:foo [1 1 2]
                                             :bar 1
                                             :qux {:a {:b [[3]]}}}}))

FAIL in () (NO_SOURCE_FILE:46)
expected: {:parent {:foo [(same :a) (same :a) (same :b)], :bar (same :a), :qux {:a {:b [[(same :b)]]}}}}
  actual: {:parent {:foo [1 1 2], :bar 1, :qux {:a {:b [[3]]}}}}
nil

Here the :as are all consistent, the :bs are 2 and 3. It'd perhaps be nice if the error reporting would say that the error was "inconsistent :b" or something?

@snoe
Copy link
Contributor Author

snoe commented May 6, 2024

@dpsutton
Updated the error to add the commented out token. I think this reads ok without weird symbols like (symbol "nil #_\"key is not present.\"") required.

(not= #_ (same :a) 1 2)

@dpsutton
Copy link
Contributor

dpsutton commented May 6, 2024

I'm not seeing any output when running the test:

(deftest foo
  (testing "foo"
    (is (=? {:foo [(=?/same :a) (=?/same :a) (=?/same :b)]
             :qux (=?/same :b)}
            {:foo [1 1 2]
             :qux 3}))))
mb.hawk.assert-exprs.approximately-equal-test=> (binding [clojure.test/*test-out* *out*] (clojure.test/run-test foo))

Testing mb.hawk.assert-exprs.approximately-equal-test

FAIL in (foo) (approximately_equal_test.clj:193)
foo
expected: {:foo [(same :a) (same :a) (same :b)], :qux (same :b)}
  actual: {:foo [1 1 2], :qux 3}

Ran 1 tests containing 1 assertions.
1 failures, 0 errors.
{:test 1, :pass 0, :fail 1, :error 0, :type :summary}

@dpsutton
Copy link
Contributor

dpsutton commented May 6, 2024

update: need to install the humane-test-output for somereason.

approximately-equal-test=> (require '[pjstadig.humane-test-output :as humane-test-output])
nil
approximately-equal-test=> (humane-test-output/activate!)
#object[clojure.lang.MultiFn 0x45a970a0 "clojure.lang.MultiFn@45a970a0"]
approximately-equal-test=> (clojure.test/run-test foo)

Testing mb.hawk.assert-exprs.approximately-equal-test

FAIL in (foo) (approximately_equal_test.clj:193)
foo
expected: {:foo [(same :a) (same :a) (same :b)], :qux (same :b)}
  actual: {:foo [1 1 2], :qux 3}
    diff: - {:qux (not= #_ (same :b) 2 3)}

Ran 1 tests containing 1 assertions.
1 failures, 0 errors.
{:test 1, :pass 0, :fail 1, :error 0, :type :summary}

@snoe snoe merged commit ac3c663 into main May 6, 2024
3 checks passed
@snoe snoe deleted the same-check branch May 6, 2024 22:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants