Zulip Chat Archive

Stream: Is there code for X?

Topic: Same test code to multiple functions


Asei Inoue (Mar 27 2024 at 16:35):

I am working on a translation of haskell 99 into Lean.
https://github.com/lean-ja/lean99

Each question has a test code attached to it, so that the test passes if the sorry is replaced by the correct implementation.
I sometimes want to present more than one example solution to a problem, but I am faced with the problem that it is difficult to use the test code all over again.

Is there a way to use the same test code for S1.f and S2.f when there are functions f with the same name in different namespaces S1 and S2?

Eric Wieser (Mar 27 2024 at 17:24):

Write your test code as a function that takes in f as input?

Asei Inoue (Mar 27 2024 at 17:31):

Write your test code as a function that takes in f as input?

That way, I end up having to write as much test code as there are functions, don't I?

In one piece of code, I want to test all functions for a given test case.

Eric Wieser (Mar 27 2024 at 17:35):

That way, I end up having to write as much test code as there are functions, don't I?

You will need to write a new testbench for every specification of the function, but not for every implementation of that specification.

Eric Wieser (Mar 27 2024 at 17:36):

I think your question would be much clearer with a mwe; what do you mean by "function"? What do you mean by "test code"?

Kyle Miller (Mar 27 2024 at 18:27):

I see that the test cases are written like

example : rotate [1, 2, 3] 3 = [1, 2, 3] := rfl

One thing is you can write this as

#guard rotate [1, 2, 3] 3 = [1, 2, 3]

which checks that this condition evaluates to true.

Kyle Miller (Mar 27 2024 at 18:31):

If you want to parameterize your tests so that you can give multiple implementations (like Eric's suggestion), here's how I might do that (though I might set up some helper functions/macros to print error messages for the individual failing tests):

def test_rotate (rotate : List α -> Nat -> List α) : Bool :=
  (rotate [1, 2, 3, 4, 5] 2 = [3, 4, 5, 1, 2])
  && (rotate [1, 2, 3] 0 = [1, 2, 3])
  && (rotate [1, 2, 3] 3 = [1, 2, 3])
  && (rotate [1, 2, 3] 1 = [2, 3, 1])

#guard test_rotate rotate
#guard test_rotate other_rotate

Asei Inoue (Mar 28 2024 at 13:26):

@Eric Wieser @Kyle Miller Thank you.

variable {α : Type}

namespace S1

def myLast (l : List α) : Option α :=
  match l with
  | [] => none
  | [a] => a
  | _ :: as => myLast as

end S1

namespace S2

def myLast (l : List α) : Option α := l.reverse |>.head?

end S2

-- The following codes are for test

example : myLast [1, 2, 3, 4] = some 4 := by rfl

example : myLast ([] : List α) = none := by rfl

example : myLast [1] = some 1 := by rfl

example : myLast ['x', 'y', 'z'] = some 'z' := by rfl

Asei Inoue (Mar 28 2024 at 13:27):

Above is the MWE, can I test S1.myLast and S2.myLast at the same time?

Eric Wieser (Mar 28 2024 at 13:49):

Here's the lowest-tech solution:

macro "#mytests " f:ident : command =>
  `(example : $f [1, 2, 3, 4] = some 4 := by rfl

    example : $f ([] : List α) = none := by rfl

    example : $f [1] = some 1 := by rfl

    example : $f ['x', 'y', 'z'] = some 'z' := by rfl)

#mytests S1.myLast

Last updated: May 02 2025 at 03:31 UTC