Re: [racket-users] Unit tests for a #lang implementation
Matthew, > If you'd like the test namespace and the test-driving module to share > the instance of the module that defines `document` (so that they'll > agree on the data structure), you can use `namespace-attach-module` to > attach the test-driving module's instance to a newly created namespace. Thanks again for a valuable pointer to the Racket documentation! This works well for modules that my test module requires directly, as in your example. I haven't been able to get any useful results for modules that are required indirectly (i.e. your module "a.rkt" requiring "c.rkt" and re-providing a struct from there). Depending on which combination of modules I run namespace-attach-module on, I either get my initial error or another one: amespace-attach-module: a different module with the same name is already in the destination namespace ; module name: "/Applications/Racket v6.10/collects/racket/pretty.rkt" None of my code refers to pretty.rkt. I think I will simply give up at this point. Compared to depending on complex stuff that I don't understand, nor want to understand, a separate testing shell script seems like the lesser evil. Thanks again, Konrad. -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Unit tests for a #lang implementation
At Thu, 31 Aug 2017 11:31:33 +0200, Konrad Hinsen wrote: > On 25/08/2017 17:03, Konrad Hinsen wrote: > > > That adds the missing piece - thanks a lot! I had seriously > > underestimated the complexity of module definitions in Racket. > > A followup mostly for the benefit of those who find this thread in the > archives one day. > > Importing a module this way works perfectly, but its utility for testing > is very limited. The problem I run into is illustrated by the following > symptom: > > raco test: (submod "lang-test.rkt" test) > document-contexts: contract violation; > given value instantiates a different structure type with the same name >expected: document? >given: (document (hash "test-context" ... > > > My code defines a structure called "document", which apparently exists > in two copies in memory. One is used by the module lang-test.rkt that > contains the tests, and the other one is used by the module that was > created from the text string. As a consequence, it is impossible to > perform any operation on the date from that module. If you'd like the test namespace and the test-driving module to share the instance of the module that defines `document` (so that they'll agree on the data structure), you can use `namespace-attach-module` to attach the test-driving module's instance to a newly created namespace. For example, with ;; a.rkt: #lang racket/base (provide (struct-out a)) (struct a (x)) ;; b.rkt: #lang racket/base (require "a.rkt") (parameterize ([current-namespace (make-base-namespace)]) (eval `(require "a.rkt")) (a-x (eval `(a 1 then you get an error a-x: contract violation; given value instantiates a different structure type with the same name expected: a? given: # but attaching the original instance of "a.rkt" avoids the error: ;; b.rkt, revised: #lang racket/base (require "a.rkt") (define-namespace-anchor here) (parameterize ([current-namespace (make-base-namespace)]) (namespace-attach-module (namespace-anchor->namespace here) '"a.rkt") (eval `(require "a.rkt")) (a-x (eval `(a 1 -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Unit tests for a #lang implementation
On 25/08/2017 17:03, Konrad Hinsen wrote: That adds the missing piece - thanks a lot! I had seriously underestimated the complexity of module definitions in Racket. A followup mostly for the benefit of those who find this thread in the archives one day. Importing a module this way works perfectly, but its utility for testing is very limited. The problem I run into is illustrated by the following symptom: raco test: (submod "lang-test.rkt" test) document-contexts: contract violation; given value instantiates a different structure type with the same name expected: document? given: (document (hash "test-context" ... My code defines a structure called "document", which apparently exists in two copies in memory. One is used by the module lang-test.rkt that contains the tests, and the other one is used by the module that was created from the text string. As a consequence, it is impossible to perform any operation on the date from that module. If all you recover from that module is basic Racket data structures, everything works fine. Konrad. -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Unit tests for a #lang implementation
On 25/08/2017 16:30, Matthew Flatt wrote: At Fri, 25 Aug 2017 16:04:01 +0200, Konrad Hinsen wrote: Putting those together, and using `current-namespace` so that both `eval-syntax` and check-module-form` use the same namespace: Thanks, that works! At least to the point of not getting any error message. I can't say if a module is actually defined. I should have suggested setting `current-module-declare-name` during evaluation of the module form, so that you get to pick the name: That adds the missing piece - thanks a lot! I had seriously underestimated the complexity of module definitions in Racket. Konrad. -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Unit tests for a #lang implementation
At Fri, 25 Aug 2017 16:04:01 +0200, Konrad Hinsen wrote: > > Putting those together, and using `current-namespace` so that both > > `eval-syntax` and check-module-form` use the same namespace: > > Thanks, that works! > > At least to the point of not getting any error message. I can't say if a > module is actually defined. I should have suggested setting `current-module-declare-name` during evaluation of the module form, so that you get to pick the name: (parameterize ([current-namespace (make-base-namespace)]) ;; Read module as a syntax object: (define mod-form (parameterize ([read-accept-lang #t] [read-accept-reader #t]) (read-syntax "test-module" (open-input-string "#lang scribble/base\n@section{Introduction}" ;; Declare the module: (parameterize ([current-module-declare-name ;; declare as name 'demo: (make-resolved-module-path 'demo)]) (eval mod-form)) ;; Access the module with `dynamic-require`, `namespace-require`, etc.: (dynamic-require ''demo 'doc)) -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Unit tests for a #lang implementation
Matthias, Matthew’s response is probably all you want in principle, but I think that your ‘unit test’ looks like another person’s ‘integration tests’. Both are useful. Wouldn’t you want to use unit tests to validate the parser independently of the macros that expand the S-expression syntax you create with the parser? If you then discover a failure, it becomes much easier to search for the bug in either of the two pieces. (I understand that there are many more pieces but let’s say ‘two’ for now.) Thanks for your reply! I guess what I want to do is somewhere in between unit and integration tests. I don't really care much about the labels. I do have unit tests for the low-level implementation details of my #lang. They are plain Racket functions with straightforward tests. What I want to write additional tests for is 1) The macros that expand the S-expression for my module 2) Some of the functions used in the expansion, for which suitable input is difficult to generate without those macros. The parser is not my problem - it's borrowed from Scribble and presumable tested by someone else :-) Konrad. -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Unit tests for a #lang implementation
Matthew, Putting those together, and using `current-namespace` so that both `eval-syntax` and check-module-form` use the same namespace: Thanks, that works! At least to the point of not getting any error message. I can't say if a module is actually defined. A plain (require 'anonymous-module) fails ("unknown module"). I tried changing the name by manipulating the s-expression returned by read-syntax, but I am never able to instantiate the module that was presumably defined by eval under that name. Is this perhaps one of those "your-identifier-is-not-from-the-scope-you-think-it-is" problems? Konrad. -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Unit tests for a #lang implementation
Konrad, Matthew’s response is probably all you want in principle, but I think that your ‘unit test’ looks like another person’s ‘integration tests’. Both are useful. Wouldn’t you want to use unit tests to validate the parser independently of the macros that expand the S-expression syntax you create with the parser? If you then discover a failure, it becomes much easier to search for the bug in either of the two pieces. (I understand that there are many more pieces but let’s say ‘two’ for now.) — Matthias > On Aug 25, 2017, at 9:17 AM, Matthew Flattwrote: > > I forgot to explain why this fails: > > At Fri, 25 Aug 2017 14:59:14 +0200, Konrad Hinsen wrote: >> (eval-syntax >> (parameterize ([read-accept-lang #t] >> [read-accept-reader #t]) >>(read-syntax "test-module" >> (open-input-string "#lang >> scribble/base\n@section[Introduction]"))) >> (module->namespace 'racket/base)) >> >> only says >> >> ; test-module::1: module: unbound identifier; >> ; also, no #%app syntax transformer is bound >> ; at: module >> >> although both module and %app are defined in racket/base. > > The `eval-syntax` function refrains from adding any scopes to the given > syntax object before trying to expand it. So, it doesn't add the scope > for the namespace's top-level bindings (unlike `eval`, which does add > that scope before trying to expand). That's why `#%app` and `module` > are not bound when trying to expand the syntax object in the above > example; the syntax object has no scopes and therefore no bindings. > > The `check-module-form` function adds a suitable scope to the `module` > binding in the given syntax object. It would work just as well to not > use `check-module-form` and to use `eval` so that the `module` binding > is taken from the namespace. > > -- > You received this message because you are subscribed to the Google Groups > "Racket Users" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to racket-users+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Unit tests for a #lang implementation
I forgot to explain why this fails: At Fri, 25 Aug 2017 14:59:14 +0200, Konrad Hinsen wrote: > (eval-syntax > (parameterize ([read-accept-lang #t] > [read-accept-reader #t]) > (read-syntax "test-module" > (open-input-string "#lang > scribble/base\n@section[Introduction]"))) > (module->namespace 'racket/base)) > > only says > > ; test-module::1: module: unbound identifier; > ; also, no #%app syntax transformer is bound > ; at: module > > although both module and %app are defined in racket/base. The `eval-syntax` function refrains from adding any scopes to the given syntax object before trying to expand it. So, it doesn't add the scope for the namespace's top-level bindings (unlike `eval`, which does add that scope before trying to expand). That's why `#%app` and `module` are not bound when trying to expand the syntax object in the above example; the syntax object has no scopes and therefore no bindings. The `check-module-form` function adds a suitable scope to the `module` binding in the given syntax object. It would work just as well to not use `check-module-form` and to use `eval` so that the `module` binding is taken from the namespace. -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Unit tests for a #lang implementation
I'd say that using `eval` or `eval-syntax` is the right idea, but: * It's better to use `make-base-namespace` instead of `module->namespace`, since `(module->namespace 'racket/base)` gives you a namespace for the inside of `racket/base` instead of a top-level namespace that has imported `racket/base`. * Use `check-module-form` from `syntax/modread` to make the `module` identifier in an S-expression module form (from `read-syntax`) is bound to the core `module` form. Putting those together, and using `current-namespace` so that both `eval-syntax` and check-module-form` use the same namespace: (require syntax/modread) (parameterize ([current-namespace (make-base-namespace)]) (eval-syntax (check-module-form (parameterize ([read-accept-lang #t] [read-accept-reader #t]) (read-syntax "test-module" (open-input-string "#lang scribble/base\n@section{Introduction}"))) 'ignored #f))) At Fri, 25 Aug 2017 14:59:14 +0200, Konrad Hinsen wrote: > Hi all, > > I have been trying for a while to write proper unit tests for a language > implementation I am working on. By "proper" tests I mean tests that are > run using raco test just like any other tests. Until now, I have a > separate shell-script based testing framework that runs scripts written > in my own #lang, but all too often I forgot to run those tests. > > For a standard s-exp based language, this is not difficult: > > (module+ test > >(module demo lazy > (provide foo) > (define (foo x) (* 2 x))) > >(require (only-in 'demo foo)) > >(check-equal? (force (foo 2)) 4)) > > But for a #lang that uses a different reader, I haven't found a working > solution yet. Even if I am willing to re-write my examples in s-exp > syntax, I run into problems: > > (module+ test > >(module example scribble/base > (section "Introduction")) > >(require (only-in 'example doc)) > >(check-equal? (force (foo 2)) 4)) > > This yields the error message > >module: no #%module-begin binding in the module's language > > Anyway, what I really want is use the #lang's standard syntax. Reading > it isn't much of a problem: > > (parameterize ([read-accept-lang #t] > [read-accept-reader #t]) > (read-syntax "test-module" > (open-input-string "#lang > scribble/base\n@section[Introduction]"))) > > But then I get a syntax-object for my module, which I need to evaluate > somehow. I'd expect eval-syntax to do the job, but... > > (eval-syntax > (parameterize ([read-accept-lang #t] > [read-accept-reader #t]) > (read-syntax "test-module" > (open-input-string "#lang > scribble/base\n@section[Introduction]"))) > (module->namespace 'racket/base)) > > only says > > ; test-module::1: module: unbound identifier; > ; also, no #%app syntax transformer is bound > ; at: module > > although both module and %app are defined in racket/base. > > Any ideas (or pointers to examples) for doing this correctly? > > Thanks in advance, >Konrad. > > -- > You received this message because you are subscribed to the Google Groups > "Racket Users" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to racket-users+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.