How does spock determine which iteratable is greater than the other? - groovy

I'm reading this doc in spock: http://spockframework.org/spock/docs/1.1/data_driven_testing.html and came across Data Variable Assignment part which has this snippet of code:
a = 3
b = Math.random() * 100
c = a > b ? a : b
but what if I tried using an iterable
a << [6, 2, 0]
b << [4, 10, 10]
c = a > b ? a : b

It doesn't.
Spock does heavy rewriting of your test specifications (by registering AST transformations with the groovy compiler).
For the where: clause it creates code to iterate over to provided lists for a and b (and assigning each value in turn to these local variables) and it runs the code for c = a > b ? a : b on each iteration.
The code transformation for the where: clause is located in the class org.spockframework.compiler.WhereBlockRewriter (https://github.com/spockframework/spock/blob/master/spock-core/src/main/java/org/spockframework/compiler/WhereBlockRewriter.java)

Related

why does clearing a list also clears all variables set to equal that list?

Using Python 3.8.10
I can from a C++ background and was doing a project in python3 where I noticed this:
a = [1,2,3,4]
b = a
a = [8]
print(b) // this gives [1,2,3,4]
but when I do a.clear
a = [1,2,3,4]
b = a
a.clear()
print(b) // this gives []
why is that?
In your second example, b is a reference to a. a.clear() mutates the underlying list to be empty, so b will also be empty. In the first example, a = [8] will assign a new list to a, but b is still pointing to the previous reference to a.
If I were to translate this to C++, the first example might look something like this. (I don't use C++ that often so this code might be weird)
std::vector<int> v1 = {1, 2, 3, 4};
std::vector<int>* a = &v1;
std::vector<int>* b = a;
std::vector<int> v2 = {8};
a = &v2;
The second example would look like
std::vector<int> v = {1, 2, 3, 4};
std::vector<int>* a = &v;
std::vector<int>* b = a;
(*a).clear();

Does the : operator create copies of list references?

Let's say I do:
>> a = [1, 2, 3]
>> b = a[:]
>> a[0] = 0
>> b
[1, 2, 3]
The statement b = a[:] clearly created a list b holding copies of the (potentially many) references that were also held by a. But the = operator only binds names and increase reference counts, so does the : operator create copies of references in Python? If so, when it comes to accessing lists, is that unique to the : operator? (e.g. indexing alone does not do that?)
Yes, the slice operator provides copies of the references, not views. See e.g.
Why are slices in Python 3 still copies and not views?.
Slicing a list in Python without generating a copy
Slicing a list without copying

Different syntax, different result

I'm trying an ultra simple novice exercise.
The objective of the exercise was to create a fibonacci pattern, I tried two methods that I thought were going to give the same result. But fires some reason they don't, I can't understand why.
Any ideas?
CODE 1
a = 0
b = 1
while b < 100:
print(b)
a = b
b = a + b
CODE 2:
a, b = 0, 1
while b < 100:
print(b)
a, b = b, a + b
In "CODE 1", a = b makes the next line equivalent to b = b + b, which is not correct.
In "CODE 2", a,b=b,a+b is essentially new_a = old_b; new_b = old_a + old_b. The new values are computed from the old values, then the new values are assigned to the variables. This computes the fibonacci series correctly.
To do it correctly in "CODE 1" a temporary variable is needed:
t = a
a = b
b = t + b # use original a saved in t to compute b
a,b=b,a+b eliminates the need for the temporary variable.

Spock: Data Pipes, and Variable Assignments

From Spock documentation:
Data tables, data pipes, and variable assignments can be combined as needed:
...
where:
a | _
3 | _
7 | _
0 | _
b << [5, 0, 0]
c = a > b ? a : b
This simple example produces a MissingPropertyException for y.
def test() {
expect:
x == 42
where:
y = 12
x << [y + 30, 54 - y]
}
What's wrong with this example?
You can't mix data pipe and variable assignment that way. Let's take a look at the source code. You can put a breakpoint in org.spockframework.runtime.ParameterizedSpecRunner class at line 49 and run the test with the debugger. You will see that currentFeature holds two parameters with names y and x:
You will also notice that there is a single dataProvider for variable name x defined:
This data provider exists because we have defined x as a data pipe, so it has to iterate over the list of variables and evaluate it in the context of data pipes. In this context it expects that y variable is also defined as a data pipe so it can take a value associated with the same index.
If you define your where: as:
where:
y << [12, 12]
x << [y + 30, 54 - y]
your test would succeed, because now y variable exists as a data provider and evaluating values for x accesses values for y using second data provider.
How to combine variable assignment with data pipes?
Consider following example:
#Unroll
def "variable assignment example"() {
expect:
x == 42
and:
c
where:
y << [12, 12]
x << [y + 30, 54 - y]
c = y < x
}
In this case variable c is evaluated twice for each element in data pipes y and x. When the first unroll happens y = 12, x = y + 30 => 12 + 30 => 42 and c evaluates to true because y<x. When the second unroll happens 12 value is assigned to y again, x evaluates to 42 (54 - y => 54 - 12 => 42) and c evaluates to true again.
Conclusion
I see that it may look like simple y = 12 variable assignment should be discovered by data pipe evaluation. Unfortunately it does not work that way. When data pipe gets evaluated it can only use values from other data pipes and any variable assignment is not seen in this context.
I think assignment y=12 is not allowed in a where block.
For example, this version works, two tests run as expected:
class SampleTest extends Specification {
#Unroll
def "test"() {
expect:
x == 42
where:
x << [12 + 30, 54 - 12]
}
}
If you absolutely need an assignment, the following will also work:
class SampleTest extends Specification {
#Unroll
def "test"() {
expect:
x == 42
where:
x << myfunc()
}
def myfunc() {
def y = 12
[y + 30, 54 - y]
}
}

How to implement a sequence of numbers, each consecutive pair adds to 4?

I have a sequence (seq) of numbers.
I want the addition of each consecutive pair of numbers to equal 4.
Below is my attempt at implementing this. But, it is wrong. The Alloy Analyzer showed me it's wrong, by generating this instance:
2, 2, -2, 4
The first pair adds to 4. (2 + 2 = 4)
The second pair does not. (2 + -2 = 0)
What is the correct way to implement this? Note: I need to use sequences (seq), so please don't change the signature or its field. I am hoping that you can show me the correct way to express the fact. Or, tell me that it's impossible to implement given the use of seq.
one sig Test {
numbers: seq Int
}
fact {
all disj n, n': Test.numbers.elems {
(plus[Test.numbers.idxOf[n], 1] = Test.numbers.idxOf[n']) =>
plus[n, n'] = 4
}
}
run {#Test.numbers.indsOf[2] > 1}
To explain why your fact is incorrect, consider the following counterexample: the Test.numbers sequence is 2, 2, 2, 4.
In that counterexample:
Test.numbers.elems evaluates to 2, 4
Test.numbers.idxOf[2] is 0 (the first index of element 2)
Test.numbers.idxOf[4] is 3
there are no two disjoint n and n' in Test.numbers.elems (i.e., {2, 4}) such that plus[Test.numbers.idxOf[n], 1] = Test.numbers.idxOf[n'] so the fact trivially holds.
The following fact should express your desired property correctly:
fact {
all i: Test.numbers.inds - (#Test.numbers).prev |
plus[Test.numbers[i], Test.numbers[i.next]] = 4
}
mySeq.inds evaluates to indexes of the sequence mySeq
i.next evaluates to i + 1
i.prev evaluates to i - 1

Resources