Julia: how to prepare and cleanup #testset - testing

I wonder what Julia best practices are to prepare and cleanup tests? Other programming languages have before and after, or similar named functions. Julia seems to be missing them.

You just write the lines in the testset. Those having #test in front of them are the tests and the other lines are the setup. As easy as that.
julia> using Test
julia> #testset "my big set" begin
x=4
y=2
#test 2y == x
end
Test Summary: | Pass Total
my big set | 1 1
Test.DefaultTestSet("my big set", Any[], 1, false)
Similarly after #test lines you can de-allocate resources etc.

You can do setup just as Przemysław proposed. However, in order to ensure proper cleanup you need to handle it manually. The reason is that if an uncaught exception is thrown within #testset but outside #test it will lead to termination immediately:
julia> #testset begin
throw(ArgumentError("something went wrong"))
#test true
#test false
end
test set: Error During Test at REPL[5]:1
Got exception outside of a #test
ArgumentError: something went wrong
...
Test Summary: | Error Total
test set | 1 1
ERROR: Some tests did not pass: 0 passed, 0 failed, 1 errored, 0 broken.
Therefore if you have some code that might throw an exception you have to handle it manually, e.g.:
julia> #testset begin
try
#test true
throw(ArgumentError("some error"))
#test false
catch
#info "caught"
finally
#info "cleanup"
end
end
[ Info: caught
[ Info: cleanup
Test Summary: | Pass Total
test set | 1 1
Test.DefaultTestSet("test set", Any[], 1, false)
(note that the second test was not run, as earlier an exception outside of #test was thrown)

Related

Testing with a metaoperator doesn't print the test description

I was writing tests on Complex arrays and I was using the Z≅ operator to check whether the arrays were approximately equal, when I noticed a missing test description.
I tried to golf the piece of code to find out the simplest case that shows the result I was seeing. The description is missing in the second test even when I use Num or Int variables and the Z== operator.
use Test;
my #a = 1e0, 3e0;
my #b = 1e0, 3e0;
ok #a[0] == #b[0], 'description1'; # prints: ok 1 - description1
ok #a[^2] Z== #b[^2], 'description2'; # prints: ok 2 -
done-testing;
Is there a simple explanation or is this a bug?
It's just precedence -- you need parens.
== is a binary op that takes a single operand on either side.
The Z metaop distributes its operator to a list on either side.
use Test;
my #a = 1e0, 3e0;
my #b = 1e0, 3e0;
ok #a[0] == #b[0], 'description1'; # prints: ok 1 - description1
ok (#a[^2] Z== #b[^2]), 'description2'; # prints: ok 2 - description2
done-testing;
Without parens, 'description2' becomes an additional element of the list on the right. And per the doc for Z:
If one of the operands runs out of elements prematurely, the zip operator will stop.

Fortran read() reads last line twice?

So, suppose I'm trying to read in a file the length of which I don't know before hand. We can use iostat and a while loop to break when we need to, but I'm having an issue with this. Namely, the code I've written reads the last line twice. I'm sure there is an obvious solution, but I can't seem to figure it out. I don't really understand how either the read() or iostat functions work entirely (I'm pretty new at fortran), but I can't glean much from documentation so I'm hoping someone here can help.
Here is the (relevant bit of) code I've written:
filename = 'test.txt'
iostat_1 = 0
iostat_2 = 0
open(newunit = lun, file = filename, status = 'old', iostat = iostat_1)
if (iostat_1 == 0) then
do while(iostat_2 == 0)
if(iostat_2 == 0) then
read(lun,*,iostat = iostat_2) dum, real_1,real_2,int_1
print *, dum, real_1,real_2,int_1
endif
enddo
endif
So, supposing my input file is
1 1.0 1.0 1
2 2.0 2.0 1
3 3.0 3.0 1
4 4.0 4.0 4
Then the output to the terminal from the print statement will be
1 1.0 1.0 1
2 2.0 2.0 1
3 3.0 3.0 1
4 4.0 4.0 4
4 4.0 4.0 4
So keep in mind the following: The main purpose here is to be able to read in a file with an arbitrary number of lines. I'm not interested in a solution involving reading the number of lines first.
Thanks for the help!
UPDATE Okay I just solved the problem. That being said, I'm wondering if there is a solution less clumsy than mine. Here is what I did to fix the issue
! Body of ReInsert
filename = 'rpriov3.dat'
iostat_1 = 0
iostat_2 = 0
open(newunit = lun, file = filename, status = 'old', iostat = iostat_1)
if (iostat_1 == 0) then
do while(iostat_2 == 0)
if(iostat_2 == 0) then
read(lun,*,iostat = iostat_2) dum, real_1,real_2,int_1
if(iostat_2 == 0) then !<---- Added this nested if statement
print *, dum, real_1,real_2,int_1
endif
print *, iostat_2
endif
enddo
endif
As you found out, when you set an iostat parameter, the read command doesn't overwrite the variables it asks for.
Your solution is, as you already noticed, somewhat convoluted.
Firstly:
do while (condition)
if (condition) then
...
end if
end do
In this case, the inner if statement is complete surplus. The loop doesn't run unless condition is true, so unless the evaluation of condition itself doesn't change the result 1), the if clause will always be executed.
The second thing I'd look at is: What should happen if the open fails? In most cases, I want to print an error and quit:
open(..., iostat=ios)
if (ios /= 0) then
print*, "Error opening file"
STOP 1
end if
do while (...)
...
end do
Even if you don't want to exit the program in case of an error in open, there are usually ways to make the code more readable than eternal nesting. For example, you could ask the user for a filename again and again (in its own loop) for a file name, until either the file opens, or the user enters some quit message.
ios = 1
do while (ios /= 0)
write(*, *, advance='no') "Enter filename (or 'quit') :"
read(*, *) filename
if ( trim(filename) == "quit" ) STOP
open(newunit=lun, file=filename, ..., iostat=ios)
end do
Finally there's the most inner if block. Since you want to exit the loop anyway when you reach an error, you can use the exit statement inside a loop to exit it immediately without executing the rest of the loop block:
do
read(..., iostat=ios) ...
if (ios /= 0) exit
print *, ....
end do
This is an infinite loop with an explicit exit as soon as it encounters a read error (usually, but not necessarily an EOF). Since the print statement is after the exit, it won't be executed in case of such an error.
1) What I mean by that is something like this C snippet i++ < 10, which both tests i against 10 and increments it.

Executing all assertions in the same Spock test, even if one of them fails

I am trying to verify two different outputs in the context of a single Spock method that runs multiple test cases of the form when-then-where. For this reason I use two assertions at the then block, as can be seen in the following example:
import spock.lang.*
#Unroll
class ExampleSpec extends Specification {
def "Authentication test with empty credentials"() {
when:
def reportedErrorMessage, reportedErrorCode
(reportedErrorMessage, reportedErrorCode) = userAuthentication(name, password)
then:
reportedErrorMessage == expectedErrorMessage
reportedErrorCode == expectedErrorCode
where:
name | password || expectedErrorMessage | expectedErrorCode
' ' | null || 'Empty credentials!' | 10003
' ' | ' ' || 'Empty credentials!' | 10003
}
}
The code is an example where the design requirement is that if name and password are ' ' or null, then I should always expect exactly the same expectedErrorMessage = 'Empty credentials!' and expectedErrorCode = 10003. If for some reason (presumably because of bugs in the source code) I get expectedErrorMessage = Empty! (or anything else other than 'Empty credentials!') and expectedErrorCode = 10001 (or anything else other than 1003), this would not satisfy the above requirement.
The problem is that if both assertions fail in the same test, I get a failing message only for the first assertion (here for reportedErrorMessage). Is it possible to get informed for all failed assertions in the same test?
Here is a piece of code that demonstrates the same problem without other external code dependencies. I understand that in this particular case it is not a good practice to bundle two very different tests together, but I think it still demonstrates the problem.
import spock.lang.*
#Unroll
class ExampleSpec extends Specification {
def "minimum of #a and #b is #c and maximum of #a and #b is #d"() {
expect:
Math.min(a, b) == c
Math.max(a, b) == d
where:
a | b || c | d
3 | 7 || 3 | 7
5 | 4 || 5 | 4 // <--- both c and d fail here
9 | 9 || 9 | 9
}
}
Based on the latest comment by OP, it looks like a solution different from my previous answer would be helpful. I'm leaving the previous answer in-place, as I feel it still provides useful information related to the question (specifically separating positive and negative tests).
Given that you want to see all failures, and not just have it fail at the first assert that fails, I would suggest concatenating everything together into a boolean AND operation. Not using the && shortcut operator, because it will only run until the first check that does not satisfy the entire operation. I would suggest using the &, so that all checks are made, regardless of any previously failing checks.
Given the max and min example above, I would change the expect block to this:
Math.min(a, b) == c & Math.max(a, b) == d
When the failure occurs, it gives you the following information:
Math.min(a, b) == c & Math.max(a, b) == d
| | | | | | | | | | |
4 5 4 | 5 false 5 5 4 | 4
false false
This shows you every portion of the failing assert. By contrast, if you used the &&, it would only show you the first failure, which would look like this:
Math.min(a, b) == c && Math.max(a, b) == d
| | | | | |
4 5 4 | 5 false
false
This could obviously get messy pretty fast if you have more than two checks on a single line - but that is a tradeoff you can make between all failing information on one line, versus having to re-run the test after fixing each individual component.
Hope this helps!
I think there are two different things at play here.
Having a failing assert in your code will throw an error, which will cease execution of the code. This is why you can't have two failing assertions in a single test. Any line of code in an expect or then block in Spock has an implicit assert before it.
You are mixing positive and negative unit tests in the same test. I ran into this before myself, and I read/watched something about this and Spock (I believe from the creator, Peter Niederwieser), and learned that these should be separated into different tests. Unfortunately I couldn't find that reference. So basically, you'll need one test for failing use cases, and one test for passing/successful use cases.
Given that information, here is your second example code, with the tests separated out, with the failing scenario in the second test.
#Unroll
class ExampleSpec extends Specification {
def "minimum of #a and #b is #c and maximum of #a and #b is #d - successes"() {
expect:
Math.min(a, b) == c
Math.max(a, b) == d
where:
a | b || c | d
3 | 7 || 3 | 7
9 | 9 || 9 | 9
}
def "minimum of #a and #b is #c and maximum of #a and #b is #d - failures"() {
expect:
Math.min(a, b) != c
Math.max(a, b) != d
where:
a | b || c | d
5 | 4 || 5 | 4
}
}
As far as your comment about the MongoDB test case - I'm not sure what the intent is there, but I'm guessing they are making several assertions that are all passing, rather than validating that something is failing.

Invalid Input Exception Handling - SmallTalk

Let a smalltalk msg named "sum" return the sum of elements in an array.
Eg: #(1 2 3 4 5) sum ----> 15
When the input is #(1 2 'a' 3 5) sum. The execution terminates and shows a big exception box.
Instead of that how can we gracefully exit the execution by just showing a message. I don't want the big exception window to be shown.
sum
|sum|
sum := 0
self do: [:a | sum := sum + a]
^sum
I tried to handle the exception the below way. However, I notice that the execution doesn't terminate in case of invalid input.
sum
|sum|
sum := 0
self do: [:a |
(a isInteger) ifFalse:[
^[Error signal] on: Exception
do: [:ex | Transcript show: 'Entered values are non-numeric. Hence comparison is not possible.']
]
sum := sum + a
]
^sum
If the below code is placed in the workspace, I expected the execution to be terminated at line 2. However, line 3 is also getting executed.
|temp|
temp := #(1 2 3 'as' 4 5) sum.
temp := temp*5.
Changing the sum method to ignore the wrong types in the input Array does not make sense. Furthermore by replacing it with a UI message you completely loose control over what kind of input is acceptable. Rather deal with these exception at the place you use sum:
[ ^ self readInput sum ]
on: Error do: [ :error| Transcript show: 'Invalid input provided for sum' ].

Maximum likelihood programming in Stata

I am trying to learn ml programming in Stata. As a part of this I am running a program myprobit (the code is adopted from Maximum likelihood estimation with Stata by Gould, Pitblado, and Sribney).
capture program drop myprobit
program define myprobit
args todo b lnf g negH g1
tempvar xb lj
mleval `xb'=`b'
quietly{
gen double `lj'=normal(`xb') if $ML_y1==1
replace `lj'=normal(-`xb') if $ML_y1==0
mlsum `lnf'=ln(`lj')
if (`todo'==0|`lnf'>= .) exit
replace `g1'= normalden(`xb')/`lj' if $ML_y1==1
replace `g1'=-normalden(`xb')/`lj' if $ML_y1==0
mlvecsum `lnf' `g'=`g1', eq(1)
if (`todo'==1|`lnf'==>.)exit
mlmatsum `lnf' `negH'=`g1'*(`g1'+`xb'),eq(1,1)
}
end
sysuse cancer, clear
gen drug2=drug==2
gen drug3=drug==3
ml model d1 myprobit (died=drug2 drug3 age)
ml check
ml maximize
But, I got an error varlist required:
Here is a trace of its execution:
------------------------------------------------------------------------------
-> myprobit 1 __000000 __000001 __000002 __000003
- `begin'
= capture noisily version 11: myprobit 1 __000000 __000001 __000002 __000003
---------------------------------------------------------------------------------------------------------------------------------- begin myprobit ---
- args todo b lnf g negH g1
- tempvar xb lj
- mleval `xb'=`b'
= mleval __000005=__000000
- quietly{
- gen double `lj'=normal(`xb') if $ML_y1==1
= gen double __000006=normal(__000005) if died==1
- replace `lj'=normal(-`xb') if $ML_y1==0
= replace __000006=normal(-__000005) if died==0
- mlsum `lnf'=ln(`lj')
= mlsum __000001=ln(__000006)
- if (`todo'==0|`lnf'>= .) exit
= if (1==0|__000001>= .) exit
- replace `g1'= normalden(`xb')/`lj' if $ML_y1==1
= replace = normalden(__000005)/__000006 if died==1
varlist required
replace `g1'=-normalden(`xb')/`lj' if $ML_y1==0
mlvecsum `lnf' `g'=`g1', eq(1)
if (`todo'==1|`lnf'==>.)exit
mlmatsum `lnf' `negH'=`g1'*(`g1'+`xb'),eq(1,1)
}
------------------------------------------------------------------------------------------------------------------------------------ end myprobit ---
- `end'
= set trace off
------------------------------------------------------------------------------
Fix myprobit.
r(100);
end of do-file
Note: The program runs without an error if likelihood evaluator is changed to do.
Any suggestion in this regard will be highly appreciated.
You provided 5 arguments to your program, but 6 are needed. Hence local macro g1 is not defined, which bites when you try to replace the variable it names.
Stata is telling you some of this. The lines
- replace `g1'= normalden(`xb')/`lj' if $ML_y1==1
= replace = normalden(__000005)/__000006 if died==1
show that local macro g1 is interpreted as nothing, i.e. an empty string, so Stata complains because it expects a variable name after replace.
The line
if (`todo'==1|`lnf'==>.)exit
is also problematic, as the operator ==> should be >=.
These are the problems I noticed; there may be others.