florence / cover

a code coverage tool for racket
MIT License
38 stars 7 forks source link

Can't cover wrapping begin in definition macros #130

Closed jackfirth closed 7 years ago

jackfirth commented 7 years ago

Given this program:

#lang racket
(require rackunit)

(define-syntax-rule (define-one id)
  (begin
    (define id 1)))

(define-one id)
(check-equal? id 1)

Cover reports that the wrapping begin in the define-one macro is uncovered. This is preventing me from achieving full coverage in some projects that use macros like this to eliminate boilerplate in a set of definitions.

florence commented 7 years ago

Cover can't because that begin doesn't exist post-expansion (when cover runs). If you raco expand that program you will see that the begin has been spliced out of existence.

If there were some syntax property that cover couldn't interpret as "please don't count this expression for or against coverage", would that help?

jackfirth commented 7 years ago

That would help, although would that require me to explicitly annotate the begin myself?

florence commented 7 years ago

Actually, I'm wrong that wont help. This is an instance of the issue where cover can't mark macro bodies as covered if the macro is not exported. If you change the program to:


#lang racket
(require rackunit)

(define-syntax (define-one stx)
  (syntax-case stx ()
    [(_ id)   #'(begin
                  (define id 1))]))

(define-one id)
(check-equal? id 1)

You will notice the body of the macro is not covered, except for the (define id 1). Whats happening is that cover isn't recording any information about the begin at all. Instead its annotating parts of the expansion of syntax inside of the expansion of the macro. If the macro body were covered, that begin would be covered. If the macro were exported and used in another module, the begin would also probably be covered.

I can think of two solutions:

  1. Somehow cover somehow cooperate with the expander to annotate macros during expansion, instead of after. I don't know if thats do-oable.

  2. Have cover perform some kind of analysis to determine if a macro is exported. If it's not, don't annotate its body (rather, mark its body as irrelevant). This solution could be made to work such that the define would still get marked as covered.

I will look into implementing 2 soon. In the mean time switching spliced begins with defines to define-values will all of the id's, or moving you macros to a separate file should work around the problem.

florence commented 7 years ago

Marking as duplicate of #133