doctest a phoenix context - testing

I'm new to elixir and phoenix and I wanted to doctest a newly created context (using mix phx.gen.context).
I have an Accounts context with a User schema.
I added to accounts_test.exs the following lines:
alias MyApp.Accounts.User
doctest MyApp.Accounts.User, import: true
And even fixed the default change_user documentation:
- %Ecto.Changeset{source: %User{}}
+ %Ecto.Changeset{data: %User{}}
But I still have many, many, errors and warnings, as if it was basically not made to be doctested...
For example, the default generated doc puts:
iex> update_user(user, %{field: new_value})
{:ok, %User{}}
This would issue:
warning: variable "new_value" does not exist and is being expanded to "new_value()"...
warning: variable "user" does not exist and is being expanded to "user()"...
test/my_app/accounts_test.exs:45: undefined function new_value/0
test/my_app/accounts_test.exs:45: undefined function user/0
My question is: is there something I'm missing? Or is it generally not common to doctest one's context (which would explain why it doesn't work out-of-the-box)

Generally speaking we do not doctest functions that have side-effects, such as context functions that have to read/write to the database, because they would require some amount of setup that is hard to cleanly portray in the doctest itself.
It is certainly doable but you should ask yourself if it is worth the effort. The Phoenix team itself seems to think it isn't. :)

Related

How can I make the origin of aliases in Cypress more apparent from the it/spec files?

My team is using aliases to set some important variables which are used within the it('Test',) blocks.
For example, we may be running the following command in a before step:
cy.setupSomeDynamicData()
Then the setupSomeDynamicData() method exists in a another file (ex: commands.js) and the setupSomeDynamicData() method may setup a couple aliases:
cypress/support/commands.js
setupSomeDynamicData() {
cy.createDynamicString(first).as('String1')
cy.createDynamicString(second).as('String2')
cy.createDynamicString(third).as('String3')
}
Now we go back to our spec/test file, and start using these aliases:
cypress/e2e/smallTest.cy.js
it('A small example test', function () {
cy.visit(this.String1)
// do some stuff...
cy.get(this.String2)
// do some stuff...
cy.visit(this.String3)
// do some stuff...
})
The problem is that unless you're the person who wrote the code, it's not obvious where this.String1, this.String2, or this.String3 are coming from nor when they were initialized (from the perspective of smallTest.cy.js) since the code that initializes the aliases is being executed in another file.
In the example, it's quite easy to Ctrl+F the codebase and search for these aliases but you have to really start doing some reverse engineering once you have more complex use cases.
I guess this feels like some sort of readability/maintainability problem because once you setup enough of these and the example I provided starts to get more complex then finding out where these aliases are created can be inconvenient. The this.* syntax makes it feel like you'd find these aliases variables somewhere within the same file in which they're being used but when you don't see any sign of them then it becomes evident that they've just magically been initialized (somewhere/somehow) and then the hunt 🕵🏼‍♂️ begins.
Some solutions that come to mind (which may be bad ideas) are:
Create JS objects with getters/setters. This way, it'll be a bit easier to trace where the variable you're using was "set"
Not use aliases, and instead, use global variables that can be imported into the spec/test files so it's clear where they are coming from then run a before/after hook to clear these variables so that the reset-per-test functionality remains.
Name the variables in a way where it's obvious that they are aliased and then spread the word/document this method within my team so that anytime they see this.aliasedString2 then they know it's coming from some method that performs these alias assignments.
I'm sure there may be a better way to handle this so just thought I'd post this question.

How can one invoke the non-extension `run` function (the one without scope / "object reference") in environments where there is an object scope?

Example:
data class T(val flag: Boolean) {
constructor(n: Int) : this(run {
// Some computation here...
<Boolean result>
})
}
In this example, the custom constructor needs to run some computation in order to determine which value to pass to the primary constructor, but the compiler does not accept the run, citing Cannot access 'run' before superclass constructor has been called, which, if I understand correctly, means instead of interpreting it as the non-extension run (the variant with no object reference in https://kotlinlang.org/docs/reference/scope-functions.html#function-selection), it construes it as a call to this.run (the variant with an object reference in the above table) - which is invalid as the object has not completely instantiated yet.
What can I do in order to let the compiler know I mean the run function which is not an extension method and doesn't take a scope?
Clarification: I am interested in an answer to the question as asked, not in a workaround.
I can think of several workarounds - ways to rewrite this code in a way that works as intended without calling run: extracting the code to a function; rewriting it as a (possibly highly nested) let expression; removing the run and invoking the lambda (with () after it) instead (funnily enough, IntelliJ IDEA tags that as Redundant lambda creation and suggests to Inline the body, which reinstates the non-compiling run). But the question is not how to rewrite this without using run - it's how to make run work in this context.
A good answer should do one of the following things:
Explain how to instruct the compiler to call a function rather than an extension method when a name is overloaded, in general; or
Explain how to do that specifically for run; or
Explain that (and ideally also why) it is not possible to do (ideally with supporting references); or
Explain what I got wrong, in case I got something wrong and the whole question is irrelevant (e.g. if my analysis is incorrect, and the problem is something other than the compiler construing the call to run as this.run).
If someone has a neat workaround not mentioned above they're welcome to post it in a comment - not as an answer.
In case it matters: I'm using multi-platform Kotlin 1.4.20.
Kotlin favors the receiver overload if it is in scope. The solution is to use the fully qualified name of the non-receiver function:
kotlin.run { //...
The specification is explained here.
Another option when the overloads are not in the same package is to use import renaming, but that won't work in this case since both run functions are in the same package.

Differences between .Bool, .so, ? and so

I’m trying to figure out what the differences are between the above-mentioned routines, and if statements like
say $y.Bool;
say $y.so;
say ? $y;
say so $y;
would ever produce a different result.
So far the only difference that is apparent to me is that ? has a higher precedence than so. .Bool and .so seem to be completely synonymous. Is that correct and (practically speaking) the full story?
What I've done to answer your question is to spelunk the Rakudo compiler source code.
As you note, one aspect that differs between the prefixes is parsing differences. The variations have different precedences and so is alphabetic whereas ? is punctuation. To see the precise code controlling this parsing, view Rakudo's Grammar.nqp and search within that page for prefix:sym<...> where the ... is ?, so, etc. It looks like ternary (... ?? ... !! ...) turns into an if. I see that none of these tokens have correspondingly named Actions.pm6 methods. As a somewhat wild guess perhaps the code generation that corresponds to them is handled by this part of method EXPR. (Anyone know, or care to follow the instructions in this blog post to find out?)
The definitions in Bool.pm6 and Mu.pm6 show that:
In Mu.pm6 the method .Bool returns False for an undefined object and .defined otherwise. In turn .defined returns False for an undefined object and True otherwise. So these are the default.
.defined is documented as overridden in two built in classes and .Bool in 19.
so, .so, and ? all call the same code that defers to Bool / .Bool. In theory classes/modules could override these instead of, or as well, as overriding .Bool or .defined, but I can't see why anyone would ever do that either in the built in classes/modules or userland ones.
not and ! are the same (except that use of ! with :exists dies) and both turn into calls to nqp::hllbool(nqp::not_i(nqp::istrue(...))). I presume the primary reason they don't go through the usual .Bool route is to avoid marking handling of Failures.
There are .so and .not methods defined in Mu.pm6. They just call .Bool.
There are boolean bitwise operators that include a ?. They are far adrift from your question but their code is included in the links above.

Module expansion of goals passed to library meta-predicates

Using SWI-Prolog (Multi-threaded, 64 bits, Version 7.3.5),
we proceed step by step:
Define dcg nonterminal a//1 in module dcgAux (pronounced: "di-SEE-goh"):
:- module(dcgAux,[a//1]).
a(0) --> [].
a(s(N)) --> [a], a(N).
Run the following queries—using phrase/2 and apply:foldl/4:
?- use_module([library(apply),dcgAux]).
true.
?- phrase( foldl( a,[s(0),s(s(0))]),[a,a,a]).
true.
?- phrase( foldl(dcgAux:a,[s(0),s(s(0))]),[a,a,a]).
true.
?- phrase(apply:foldl(dcgAux:a,[s(0),s(s(0))]),[a,a,a]).
true.
?- phrase(apply:foldl( a,[s(0),s(s(0))]),[a,a,a]).
ERROR: apply:foldl_/4: Undefined procedure: apply:a/3
нет! Quite a surprise—and not a good one. Have we been missing some unknown unknowns?
To get rid of above irritating behavior, we must first find out the reason(s) causing it:
?- import_module(apply,M), M=user.
false.
?- phrase(apply:foldl(a,[s(0),s(s(0))]),[a,a,a]).
ERROR: apply:foldl_/4: Undefined procedure: apply:a/3
?- add_import_module(apply,user,end).
true.
?- import_module(apply,M), M=user. % sic!
M = user. % `?- import_module(apply,user).` fails!
?- phrase(apply:foldl(a,[s(0),s(s(0))]),[a,a,a]).
true.
What's going on? The way I see it is this:
Module expansion of the goal passed to foldl/4 is limited.
Quoting from the SWI-Prolog manual page on import_module/2:
All normal modules only import from user, which imports from system.
SWI's library(apply) only "inherits" from system, but not user.
If we clone module apply to applY (and propagate the new module name), we observe:
?- use_module(applY).
true.
?- phrase(applY:foldl(a,[s(0),s(s(0))]),[a,a,a]). % was: ERROR
true. % now: OK!
Please share your ideas on how I could/should proceed!
(I have not yet run a similar experiment with other Prolog processors.)
This is an inherent feature/bug of predicate based module systems in the Quintus tradition. That is, this module system was first developed for Quintus Prolog. It was adopted subsequently by SICStus (after 0.71), then (more or less) by 13211-2, then by YAP, and (with some modifications) by SWI.
The problem here is what exactly an explicit qualification means. As long as the goal is no meta-predicate, things are trivially resolvable: Take the module of the innermost qualification. However, once you have meta-predicates, the meta-arguments need to be informed of that module ; or not. If the meta-arguments are informed, we say that the colon sets the calling context, if not, then some other means is needed for that purpose.
In Quintus tradition, the meta-arguments are taken into account. With the result you see. As a consequence you cannot compare two implementations of the same meta-predicate in the same module directly. There are other approaches most notably IF and ECLiPSe that do not change the calling context via the colon. This has advantages and disadvantages. The best is to compare them case by case.
Here is a recent case. Take lambdas and how they are put into a module
in SICStus, in SWI, and in ECLiPSe.
As for the Quintus/SICStus/YAP/SWI module system, I'd rather use it in the most conservative manner possible. That is:
no explicit qualification, consider the infix : as something internal
clean, checkable meta-declarations - insert on purpose an undefined predicate just to see whether or not cross-referencing is able to detect the problem (in SWI that's check or make).
use the common subset, avoid the many bells and whistles - there are many well meant extensions...
do more versatile things the pedestrian way: reexport by adding an appropriate module and add a dummy definition. Similarly, instead of renaming, import things from an interface module.
be always aware that module systems have inherently some limits. No matter how you twist or turn it. There is no completely seamless module system, for the very purpose of modules is to separate code and concerns.
1: To be precise, SICStus' adaptation of Quintus modules did only include : for module sensitive arguments in meta_predicate declarations. The integers 0..9, which are so important for higher-order programming based on call/N were only introduced about 20 years later in
4.2.0 released 2011-03-08.

Why does Clojure 1.3 say that variables aren't declared dynamic when I have declared them to be dynamic? [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I'm porting working Clojure code (in a Leiningen project) from 1.2 to 1.3 and having problems. In addition to the code itself no longer working, I'm getting dozens of warning messages like this one:
Warning: *tooltip-width* not declared dynamic and thus is not dynamically rebindable,
but its name suggests otherwise. Please either indicate ^:dynamic *tooltip-width*
or change the name.
This is happening even though I have already made what look like the correct modifications to vars that I'm using to maintain state. For the error above, for example, the code already includes this:
(def ^:dyanamic *tooltip-width* (* 1.8 *slip-width*))
I get these errors in two places: first, from the command line, as a result of executing lein swank; and second, from the Emacs REPL, after compiling my core.clj file using C-c C-w.
To be absolutely complete, here is my project.clj file:
(defproject infwb "1.0.0-SNAPSHOT"
:description "an evolving, experimental workspace for manipulating infocards"
:main infwb.core
:dependencies [[org.clojure/clojure "1.3"]
[seesaw "1.2.1"]
[org.clojars.gw666/sxqj "beta2"]
[org.clojars.gw666/piccolo2dcore "1.3"]
[org.clojars.gw666/piccolo2dextras "1.3"]
[com.miglayout/miglayout "3.7.4"]
]
:dev-dependencies [[swank-clojure "1.3.2"]
[org.clojars.weavejester/autodoc "0.9.0"]]
:autodoc {:name "Infocard Workbench (InfWb)",
:web-src-dir "https://github.com/gw666/infwb/blob"})
In addition to getting my code working, I'd like to understand why I'm getting these errors and why I'm getting them in both places. Thanks for your help.
It's a simple typo.
(def ^:dyanamic ...
should be:
(def ^:dynamic ...
Happens to us all!
You might want to consider using refs or atoms instead of vars to maintain state.
To quote the Clojure documentation:
Vars provide a mechanism to refer to a mutable storage location that can be dynamically rebound (to a new storage location) on a per-thread basis.
(Emphasis mine.)
Vars can be set to a new value (for the current thread) with the binding macro. Up to Clojure 1.2 any var could be rebound like this, but since Clojure 1.3 vars need to be explicitly declared as ^:dynamic to allow this. (As far as I know, the reason is a drastic speed-up of var look-ups for the common case of no rebinding.)
It is a common convention (but nothing more) to give vars that are intended to be rebound names like this: *foobar*. Because of this convention, the compiler gives you a warning when it sees a var named like this that is not declared dynamic.
To sum up:
If you just want to declare a value that does not change during runtime, use a var and drop the *'s around the name.
If you want to change the value on a per-thread basis, declare the var dynamic.
If you want to maintain global state (not per-thread), use one of the other referential types: atom, ref (if you need transactions) or agent (for asynchronous change).