racket / rackunit

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

expected / actual interaction with pretty-printing

rfindler opened this issue · comments

Sometimes, rackunit inserts newlines into expected and actual results when using check-equal? (which is great!) but the indentation has issues. For example, this program:

#lang racket
(require rackunit)
(check-equal?
 (make-list 10 'xfdjkalf)
 (make-list 11 'xfdjkalf))

produces this output:

--------------------
. FAILURE
name:       check-equal?
location:   unsaved-editor:3:0
actual:     '(xfdjkalf
  xfdjkalf
  xfdjkalf
  xfdjkalf
  xfdjkalf
  xfdjkalf
  xfdjkalf
  xfdjkalf
  xfdjkalf
  xfdjkalf)
expected:   '(xfdjkalf
  xfdjkalf
  xfdjkalf
  xfdjkalf
  xfdjkalf
  xfdjkalf
  xfdjkalf
  xfdjkalf
  xfdjkalf
  xfdjkalf
  xfdjkalf)
--------------------
> 

I think that the printer should either detect that there are newlines in the printed result and, in tht case, lead with a newline, or it should set various printing parameters so that everything is indented past the "expected". Probably the former is best! But maybe a hybrid, where you put that first newline in, but then indent everything by one space or something so that the words "expected" and "actual" stand out.

There are two ways we could do this:

  1. Make everything pretty-printed, and use a pretty version of the format function instead of format in check-info->string.
  2. Try set the pretty-print-print-line parameter to print the extra padding after the newline.

Strategy (1) can be accomplished with a function like this:

(require (rename-in racket/pretty [pretty-format pretty-string]))

;; exactly like format, but pretty (*not* the same as pretty-format from racket/pretty)
(define (pretty-format fmt . vs)
  (pretty-string (formatted fmt vs)))

(struct formatted (fmt vs)
  #:methods gen:custom-write
  [(define (write-proc this out mode)
     (apply fprintf out (formatted-fmt this) (formatted-vs this)))])

;; using it produces:
actual:     '(xfdjkalf
              xfdjkalf
              xfdjkalf
              xfdjkalf
              xfdjkalf
              xfdjkalf
              xfdjkalf
              xfdjkalf
              xfdjkalf
              xfdjkalf)

I also attempted strategy (2) with the function below, but the indentation wasn't right for any of the sub-expressions:

(define (call-with-pretty-padding pad thunk)
  ;; the old and new value of the parameter
  (define old-newline (pretty-print-print-line))
  (define (new-newline line-num out prev-len dest-cols)
    (+ (old-newline line-num out prev-len dest-cols)
       (if (zero? line-num)
           0
           (write-string pad out))))
  (parameterize ([pretty-print-print-line new-newline])
    (thunk)))

;; using it produces:
actual:     '(xfdjkalf
            xfdjkalf
            xfdjkalf
            xfdjkalf
            xfdjkalf
            xfdjkalf
            xfdjkalf
            xfdjkalf
            xfdjkalf
            xfdjkalf)

I think that you could monitor the output at the port level to see if you see a newline and, if you do, restart the printing (but this time putting a newline after the word "expected:"), perhaps with a modest indentation (one or two characters) on each line.

As for the indenting-not-quite-right issue, I can't recall exactly how that goes either, but I think that I figured it out once before and used it in redex here:

https://github.com/racket/redex/blob/master/redex-lib/redex/private/reduction-semantics.rkt#L3140

maybe that helps?

Or, there's the string-indent function, already there for nested-info values. That seems simpler than either strategy.

I don't know that function, but shame on me for going directly to the efficient solution before a need for it exists. :)

Thanks!