Re: [2/3] gdiplus: fix GdipPathIterNextMarker behaviour on path without markers. fix tests.

2008-07-13 Thread Alexandre Julliard
Nikolay Sivov [EMAIL PROTECTED] writes:

 I don't think so. If the call fails testing return value doesn't make 
 any sense. In this case 'result' is uninitialized and remains 
 uninitialized after a call if it fails (here I mean a native too). So 
 why should we check something which has unpredictable value?
 By the way first time I saw this here 
 8fd6f0e26ae28f2ba4938e2fbcc4851f47baa53c..

The difference is that this was a todo_wine, so it's expected to fail
and we don't want to test uninitialized data since that can cause random
test failures.

In your case the test is expected to succeed, so the only way you'll get
uninitialized data is when the first test fails, and then it doesn't
matter if we get a random second failure, the test failed already.

-- 
Alexandre Julliard
[EMAIL PROTECTED]




Re: [2/3] gdiplus: fix GdipPathIterNextMarker behaviour on path without markers. fix tests.

2008-07-13 Thread Nikolay Sivov
Alexandre Julliard wrote:
 Nikolay Sivov [EMAIL PROTECTED] writes:

   
 I don't think so. If the call fails testing return value doesn't make 
 any sense. In this case 'result' is uninitialized and remains 
 uninitialized after a call if it fails (here I mean a native too). So 
 why should we check something which has unpredictable value?
 By the way first time I saw this here 
 8fd6f0e26ae28f2ba4938e2fbcc4851f47baa53c..
 

 The difference is that this was a todo_wine, so it's expected to fail
 and we don't want to test uninitialized data since that can cause random
 test failures.

 In your case the test is expected to succeed, so the only way you'll get
 uninitialized data is when the first test fails, and then it doesn't
 matter if we get a random second failure, the test failed already.

   
I see. I've just reposted it with 'try3' label, there's no linking based 
on return value now. Now I'm explicitly initialize output before each 
call to be sure that values changed or not.

What do you think about matrix comparison or in general float comparison 
implementation? What is the best way to implement this. We have two 
cases now:

1. GdipIsMatrixEqual which compares two matrices (with simple bitwise 
operation now)
2. GdipIsMatrixInvertible which contains a check for 'not above zero' 
determinant.

I think first of all we should choose an appropriate method to do so and 
only after that try to compare results with native. What do you think of 
that?






Re: [2/3] gdiplus: fix GdipPathIterNextMarker behaviour on path without markers. fix tests.

2008-07-13 Thread Michael Karcher
Am Sonntag, den 13.07.2008, 12:42 +0400 schrieb Nikolay Sivov:
 I think first of all we should choose an appropriate method to do so and 
 only after that try to compare results with native. What do you think of 
 that?
That might a good approach if we want to implement some new API and want
to do it sensibly. That's the point where design questions are asked.
But the Wine project works the other way round: Wine is bug-for-bug
compatible with Microsoft Windows. This means we have to design the same
way as Microsoft, whether we think this behaviour is idiotic or not.

[Next paragraph is generally about Wine development. I do not imply that
you are going to violate the rules stated here or already have sone so.
Its just for your (or everybody who reads this mail in the archive)
information]
So: First you try out what native does. And I mean *try* *out*, not
reverse engineer by disassembling. To proof that you have tried out what
native does, you publish your tests as wine testcases. Then you
implement wine in a way these testcases pass. For myself, I think it is
acceptable to implement some API without comparing to native first, if
you get an application to run by that, *but* to get this patch included,
you better write an API test that shows how that application used the
API you changed (or implemented) and verifies that your implementation
not just happen to make the application run, but really returns the same
result as native does. If you post a patch, always be prepared to be
asked to test further cases. It greatly increases your chance to get
your patch committed if you add these further cases (often, they show
deficiencies in your patch then). Modify your patch to make these tests
pass too, or (with a convincing explanation why this would be
out-of-scope for your patch, for example needing to implement a whole
new thing to make it pass) include the test as todo_wine. Do never
ignore a test request because your implementation of an API fails it. As
explained above: The point What nativce does is an extremely stupid way
to handle these corner cases, my implementation if much smarter about
it is never valid for Wine.

I made the explicit note about disassembling (be it with IDA, w32dasm or
getting an assembler listing of Microsoft dlls with some debugger),
because for legal reasons, developers that have seen Microsoft source or
object code are not allowed to commit code to Wine anymore. IIRC there
is no consensus yet to what extent this rule applies, but (IIRC again)
the usual interpretation is you may not contribute to the dll you
disassembled.

Regards,
  Michael Karcher





Re: [2/3] gdiplus: fix GdipPathIterNextMarker behaviour on path without markers. fix tests.

2008-07-13 Thread Nikolay Sivov
Reece Dunn wrote:
 2008/7/13 Nikolay Sivov [EMAIL PROTECTED]:
   
 What do you think about matrix comparison or in general float comparison
 implementation? What is the best way to implement this. We have two
 cases now:

 1. GdipIsMatrixEqual which compares two matrices (with simple bitwise
 operation now)
 

 Is this the way it works on Windows? You have 4 basic cases:
 a.  exactly equal;
 b.  equal + epsilon for rounding/representation errors;
 c.  equal - epsilon for rounding/representation errors;
 d.  not equal.

 The code at the moment covers a and d (is there a test for d?), but
 what about b and c? These would be useful, because if the Windows
 version of GdipIsMatrixEqual *is* catering for error of a given
 epsilon, then you can use that function for validation. If not, you
 have tests that prove that Windows is using a simplistic comparison
 method.
   
Exactly, so I plan to test this deeper on native. As I see now after 
some basic tests, most probably native call does a bitwise comparison 
cause the result is affected by a smallest matrix element change (e.g. 
1.000f - 1.001f). But I'll test it more. Reece, do you have any 
suggestions to do some bounds test (I mean test is call affected by 
representation or round errors or not)?
 2. GdipIsMatrixInvertible which contains a check for 'not above zero'
 determinant.
 

 It has been a while since I have done any matrix math. I'll assume
 that the above is the correct definition/check for invertible (makes
 sense because you have inv(a(ij)) = a(ij)/det(A), so can't have det(A)
 == 0).

 Now here, you have several 'classes' of matrices w.r.t. whether they
 are invertible or not:
 a.  det(A)  0
 b.  det(A) == 0
 c.  det(A)  0

 So does Windows match your assumption for the answer to these (a ==
 yes; b, c == no).
   
What do you mean here by (c = no)? Native allows negative det and I do so.
 I think first of all we should choose an appropriate method to do so and
 only after that try to compare results with native. What do you think of
 that?
 

 Are you saying that GdipIsMatrixInvertible should be used for
 comparison of two matrices? If so, you can have two different matrices
 that are invertible, so it does not make sense.
   
Where did I say that? It's weird.
 A good first step would be to print out the expected and returned
 values for the matrices, and keep the GdipIsMatrixEqual check. This
 will allow you to determine if the reason this is failing is due to
 rounding errors, or that they are completely different results.

 - Reece
   
With last patch marked 'try3' 
http://www.winehq.org/pipermail/wine-patches/2008-July/057797.html
test and crosstest work for me cause there aren't affected by 
representation errors using det == 16..




Re: [2/3] gdiplus: fix GdipPathIterNextMarker behaviour on path without markers. fix tests.

2008-07-13 Thread Nikolay Sivov
Michael Karcher wrote:
 Am Sonntag, den 13.07.2008, 12:42 +0400 schrieb Nikolay Sivov:
   
 I think first of all we should choose an appropriate method to do so and 
 only after that try to compare results with native. What do you think of 
 that?
 
 That might a good approach if we want to implement some new API and want
 to do it sensibly. That's the point where design questions are asked.
 But the Wine project works the other way round: Wine is bug-for-bug
 compatible with Microsoft Windows. This means we have to design the same
 way as Microsoft, whether we think this behaviour is idiotic or not.

 [Next paragraph is generally about Wine development. I do not imply that
 you are going to violate the rules stated here or already have sone so.
 Its just for your (or everybody who reads this mail in the archive)
 information]
 So: First you try out what native does. And I mean *try* *out*, not
 reverse engineer by disassembling. To proof that you have tried out what
 native does, you publish your tests as wine testcases. Then you
 implement wine in a way these testcases pass. For myself, I think it is
 acceptable to implement some API without comparing to native first, if
 you get an application to run by that, *but* to get this patch included,
 you better write an API test that shows how that application used the
 API you changed (or implemented) and verifies that your implementation
 not just happen to make the application run, but really returns the same
 result as native does. If you post a patch, always be prepared to be
 asked to test further cases. It greatly increases your chance to get
 your patch committed if you add these further cases (often, they show
 deficiencies in your patch then). Modify your patch to make these tests
 pass too, or (with a convincing explanation why this would be
 out-of-scope for your patch, for example needing to implement a whole
 new thing to make it pass) include the test as todo_wine. Do never
 ignore a test request because your implementation of an API fails it. As
 explained above: The point What nativce does is an extremely stupid way
 to handle these corner cases, my implementation if much smarter about
 it is never valid for Wine.

 I made the explicit note about disassembling (be it with IDA, w32dasm or
 getting an assembler listing of Microsoft dlls with some debugger),
 because for legal reasons, developers that have seen Microsoft source or
 object code are not allowed to commit code to Wine anymore. IIRC there
 is no consensus yet to what extent this rule applies, but (IIRC again)
 the usual interpretation is you may not contribute to the dll you
 disassembled.

 Regards,
   Michael Karcher
   
All of this is absolutely clear. The only reason why my last tests fail 
was that I didn't check them on native thinking that a crossbuild is 
much complicated procedure that it is in fact.
Of course I will not reverse any Windows binary to look at it cause it's 
a direct License Agreement  violation.

With this question I didn't try to bring some incompatibility with a 
'better' implementation, not equivalent with native. Of course not. I've 
just asked the possible way to start with this problem of portable 
floating point comparison. If  I'll found that native use some 'not 
bitwise' comparison for this calls I'll have to use some comparison 
method with tolerance value(s) and then try to get the same results as 
native provides. The question was 'what method is preferable in this 
case' that's all.




Re: [2/3] gdiplus: fix GdipPathIterNextMarker behaviour on path without markers. fix tests.

2008-07-13 Thread Michael Karcher
Am Sonntag, den 13.07.2008, 13:51 +0400 schrieb Nikolay Sivov:
 Reece Dunn wrote:
  Is this the way it works on Windows? You have 4 basic cases:
  a.  exactly equal;
  b.  equal + epsilon for rounding/representation errors;
  c.  equal - epsilon for rounding/representation errors;
  d.  not equal.
I don't see a difference between b and c. A matrix has four elements.
Some might be slightly too big and others slightly too small. Would this
make b or c? It's just one case: equal +/- epsilon.

 Exactly, so I plan to test this deeper on native. As I see now after 
 some basic tests, most probably native call does a bitwise comparison 
 cause the result is affected by a smallest matrix element change (e.g. 
 1.000f - 1.001f). But I'll test it more.
1+FLT_EPSILON is the value to use for the smallest matrix element
change. But sour test already is a very strong indication that it
really is strict equality test. FLT_EPSILON is in float.h

 Reece, do you have any 
 suggestions to do some bounds test (I mean test is call affected by 
 representation or round errors or not)?
Another thing you could test is: Is the Matrix (1,FLT_EPSILON/2,0,1)
equal to (1,0,0,1). A matrix like te former can easily be the result of
multiplying a matrix by its inverse matrix (if represented as floating
point numbers). One might expect that the product of a matrix and its
inverse always is the identity matrix.

  2. GdipIsMatrixInvertible which contains a check for 'not above zero'
  determinant.
  
  a.  det(A)  0
  b.  det(A) == 0
  c.  det(A)  0
 
  So does Windows match your assumption for the answer to these (a ==
  yes; b, c == no).   
 What do you mean here by (c = no)? Native allows negative det and I do so.
He implied it form your not above zero quote. A hint how I would
implement that test (if it turns out that a strict comparison to 0 is
not the right result): Do not calculate the sum of a*d and -b*c, but
compare these numbers in a sensible way.

Regards,
  Michael Karcher





Re: [2/3] gdiplus: fix GdipPathIterNextMarker behaviour on path without markers. fix tests.

2008-07-13 Thread Michael Karcher
Am Sonntag, den 13.07.2008, 14:09 +0400 schrieb Nikolay Sivov:
 Michael Karcher wrote:
  Am Sonntag, den 13.07.2008, 12:42 +0400 schrieb Nikolay Sivov:   
  I think first of all we should choose an appropriate method to do so and 
  only after that try to compare results with native. What do you think of 
  that?
[ Deleted quotes about how to work on Wine ]
 All of this is absolutely clear.
OK. Won't tell it to you again.

 With this question I didn't try to bring some incompatibility with a 
 'better' implementation, not equivalent with native.
You have written that we should choose an appropriate method. We can
not choose an appropriate method. Microsoft has chosen one. We have to
find out which. And it might be different for GdipIsMatrixInvertible and
GdipIsMatrixEqual.

Regards,
  Michael Karcher





Re: [2/3] gdiplus: fix GdipPathIterNextMarker behaviour on path without markers. fix tests.

2008-07-13 Thread Reece Dunn
2008/7/13 Nikolay Sivov [EMAIL PROTECTED]:

 What do you think about matrix comparison or in general float comparison
 implementation? What is the best way to implement this. We have two
 cases now:

 1. GdipIsMatrixEqual which compares two matrices (with simple bitwise
 operation now)

Is this the way it works on Windows? You have 4 basic cases:
a.  exactly equal;
b.  equal + epsilon for rounding/representation errors;
c.  equal - epsilon for rounding/representation errors;
d.  not equal.

The code at the moment covers a and d (is there a test for d?), but
what about b and c? These would be useful, because if the Windows
version of GdipIsMatrixEqual *is* catering for error of a given
epsilon, then you can use that function for validation. If not, you
have tests that prove that Windows is using a simplistic comparison
method.

 2. GdipIsMatrixInvertible which contains a check for 'not above zero'
 determinant.

It has been a while since I have done any matrix math. I'll assume
that the above is the correct definition/check for invertible (makes
sense because you have inv(a(ij)) = a(ij)/det(A), so can't have det(A)
== 0).

Now here, you have several 'classes' of matrices w.r.t. whether they
are invertible or not:
a.  det(A)  0
b.  det(A) == 0
c.  det(A)  0

So does Windows match your assumption for the answer to these (a ==
yes; b, c == no).

 I think first of all we should choose an appropriate method to do so and
 only after that try to compare results with native. What do you think of
 that?

Are you saying that GdipIsMatrixInvertible should be used for
comparison of two matrices? If so, you can have two different matrices
that are invertible, so it does not make sense.

A good first step would be to print out the expected and returned
values for the matrices, and keep the GdipIsMatrixEqual check. This
will allow you to determine if the reason this is failing is due to
rounding errors, or that they are completely different results.

- Reece




Re: [2/3] gdiplus: fix GdipPathIterNextMarker behaviour on path without markers. fix tests.

2008-07-13 Thread Nikolay Sivov
Michael Karcher wrote:
 Am Sonntag, den 13.07.2008, 13:51 +0400 schrieb Nikolay Sivov:
   
 Reece Dunn wrote:
 
 Is this the way it works on Windows? You have 4 basic cases:
 a.  exactly equal;
 b.  equal + epsilon for rounding/representation errors;
 c.  equal - epsilon for rounding/representation errors;
 d.  not equal.
   
 I don't see a difference between b and c. A matrix has four elements.
 Some might be slightly too big and others slightly too small. Would this
 make b or c? It's just one case: equal +/- epsilon.

   
 Exactly, so I plan to test this deeper on native. As I see now after 
 some basic tests, most probably native call does a bitwise comparison 
 cause the result is affected by a smallest matrix element change (e.g. 
 1.000f - 1.001f). But I'll test it more.
 
 1+FLT_EPSILON is the value to use for the smallest matrix element
 change. But sour test already is a very strong indication that it
 really is strict equality test. FLT_EPSILON is in float.h
   
This header is optional, isn't it? I've used FLT_EPSILON in call PlgBlt 
of gdi32, but it was replaced with 1e-5 on commit (it was fabs(det)  
FLT_EPSILON). So am I right that we can't use it on portability reason?
 Reece, do you have any 
 suggestions to do some bounds test (I mean test is call affected by 
 representation or round errors or not)?
 
 Another thing you could test is: Is the Matrix (1,FLT_EPSILON/2,0,1)
 equal to (1,0,0,1). A matrix like te former can easily be the result of
 multiplying a matrix by its inverse matrix (if represented as floating
 point numbers). One might expect that the product of a matrix and its
 inverse always is the identity matrix.
   
I'll try that.
 2. GdipIsMatrixInvertible which contains a check for 'not above zero'
 determinant.
 
 
 a.  det(A)  0
 b.  det(A) == 0
 c.  det(A)  0

 So does Windows match your assumption for the answer to these (a ==
 yes; b, c == no).   
   
 What do you mean here by (c = no)? Native allows negative det and I do so.
 
 He implied it form your not above zero quote.
Yes, I meant absolute value of course.
  A hint how I would
 implement that test (if it turns out that a strict comparison to 0 is
 not the right result): Do not calculate the sum of a*d and -b*c, but
 compare these numbers in a sensible way.
   
Here I something like FLT_EPSILON constant. So it's the same like above.
 Regards,
   Michael Karcher

   





Re: [2/3] gdiplus: fix GdipPathIterNextMarker behaviour on path without markers. fix tests.

2008-07-13 Thread Michael Karcher
Am Sonntag, den 13.07.2008, 18:43 +0400 schrieb Nikolay Sivov:
  Exactly, so I plan to test this deeper on native. As I see now after 
  some basic tests, most probably native call does a bitwise comparison 
  cause the result is affected by a smallest matrix element change (e.g. 
  1.000f - 1.001f). But I'll test it more.
  1+FLT_EPSILON is the value to use for the smallest matrix element
  change. But sour test already is a very strong indication that it
  really is strict equality test. FLT_EPSILON is in float.h
 This header is optional, isn't it? I've used FLT_EPSILON in call PlgBlt 
 of gdi32, but it was replaced with 1e-5 on commit (it was fabs(det)  
 FLT_EPSILON).
To the best of my knowledge and the web pages I found on this topic,
float.h is standard ANSI C. There should be no need to avoid this
header.

On the other hand, I don't understand why you use 1e-5 or FLT_EPSILON at
that point at all. If I am not totally confused, you calculate some kind
of determinant from the nRect entries, which were directly before
initialized from the nXSrc, nYSrc, nWidth, nHeight variables, which are
integers, so rect contains integer values. The formula for det only
contains subtraction and multiplication. How do you expect that the
outcome of this calculation is non-integral?

   A hint how I would
  implement that test (if it turns out that a strict comparison to 0 is
  not the right result): Do not calculate the sum of a*d and -b*c, but
  compare these numbers in a sensible way.   
 Here I something like FLT_EPSILON constant. So it's the same like above.
Be aware that 2+FLT_EPSILON stored into a float still is 2! You do not
want to write fabs(a*d-b*c)  FLT_EPSILON.

Try this:


#include float.h
#include stdio.h

float det(float a, float b, float c, float d)
{
  return fabs(a*b-c*d);
}

int main(void)
{
  printf(%g %g\n,det(100./3,120./7,12000./21,1), FLT_EPSILON);
}


compiled with no optimization (to avoid the compiler pre-calculating the
determinant with higher precision). You will see that the difference is
*much* bigger than FLT_EPSILON, yet the matrix was intended to be
singular (and were singular if there were no rounding errors on the
thirds). You should understand the cause of this before you try to write
a robust float comparison function.

Regards,
  Michael Karcher






Re: [2/3] gdiplus: fix GdipPathIterNextMarker behaviour on path without markers. fix tests.

2008-07-12 Thread James Hawkins
On Sat, Jul 12, 2008 at 11:56 AM, Nikolay Sivov [EMAIL PROTECTED] wrote:
 Changelog:
-  Fix GdipPathIterNextMarker behaviour on path without markers. Make 
 tests pass on native.

 ---
  dlls/gdiplus/pathiterator.c   |3 ++-
  dlls/gdiplus/tests/pathiterator.c |6 +++---
  2 files changed, 5 insertions(+), 4 deletions(-)

 diff --git a/dlls/gdiplus/pathiterator.c b/dlls/gdiplus/pathiterator.c
 index 55b0782..3d3b1dc 100644
 --- a/dlls/gdiplus/pathiterator.c
 +++ b/dlls/gdiplus/pathiterator.c
 @@ -140,7 +140,8 @@ GpStatus WINGDIPAPI 
 GdipPathIterNextMarker(GpPathIterator* iterator, INT *result
 /* first call could start with second point as all subsequent, cause
path couldn't contain only one */
 for(i = iterator-marker_pos + 1; i  iterator-pathdata.Count; i++){
 -if(iterator-pathdata.Types[i]  PathPointTypePathMarker){
 +if((iterator-pathdata.Types[i]  PathPointTypePathMarker) ||
 +   (i == iterator-pathdata.Count - 1)){
 *startIndex = iterator-marker_pos;
 if(iterator-marker_pos  0) (*startIndex)++;
 *endIndex   = iterator-marker_pos = i;
 diff --git a/dlls/gdiplus/tests/pathiterator.c 
 b/dlls/gdiplus/tests/pathiterator.c
 index 071c1d5..6498bb3 100644
 --- a/dlls/gdiplus/tests/pathiterator.c
 +++ b/dlls/gdiplus/tests/pathiterator.c
 @@ -114,7 +114,7 @@ static void test_nextmarker(void)
 GdipCreatePathIter(iter, path);
 stat = GdipPathIterNextMarker(iter, result, start, end);
 expect(Ok, stat);
 -expect(0, result);
 +if(stat == Ok) expect(TRUE, (result == 4)  (start == 0)  (end == 3));

Why are you checking if stat == Ok?  You're linking what should be
separate tests together.  You also need to put each of these checks
into separate tests.  If the test fails, you have no idea (without
debugging further) which one of those checks fails.  They're called
unit tests for a reason.

 GdipDeletePathIter(iter);

 /* one marker */
 @@ -125,7 +125,7 @@ static void test_nextmarker(void)
 expect(TRUE, (start == 0)  (end == 3)  (result == 4));
 stat = GdipPathIterNextMarker(iter, result, start, end);
 expect(Ok, stat);
 -expect(0, result);
 +if(stat == Ok) expect(0, result);

Same thing as above.

 GdipDeletePathIter(iter);

 /* two markers */
 @@ -140,7 +140,7 @@ static void test_nextmarker(void)
 expect(TRUE, (start == 4)  (end == 5)  (result == 2));
 stat = GdipPathIterNextMarker(iter, result, start, end);
 expect(Ok, stat);
 -expect(0, result);
 +if(stat == Ok) expect(0, result);

Same.

-- 
James Hawkins




Re: [2/3] gdiplus: fix GdipPathIterNextMarker behaviour on path without markers. fix tests.

2008-07-12 Thread Nikolay Sivov
James Hawkins wrote:
 On Sat, Jul 12, 2008 at 11:56 AM, Nikolay Sivov [EMAIL PROTECTED] wrote:
   
 Changelog:
-  Fix GdipPathIterNextMarker behaviour on path without markers. Make 
 tests pass on native.

 ---
  dlls/gdiplus/pathiterator.c   |3 ++-
  dlls/gdiplus/tests/pathiterator.c |6 +++---
  2 files changed, 5 insertions(+), 4 deletions(-)

 diff --git a/dlls/gdiplus/pathiterator.c b/dlls/gdiplus/pathiterator.c
 index 55b0782..3d3b1dc 100644
 --- a/dlls/gdiplus/pathiterator.c
 +++ b/dlls/gdiplus/pathiterator.c
 @@ -140,7 +140,8 @@ GpStatus WINGDIPAPI 
 GdipPathIterNextMarker(GpPathIterator* iterator, INT *result
 /* first call could start with second point as all subsequent, cause
path couldn't contain only one */
 for(i = iterator-marker_pos + 1; i  iterator-pathdata.Count; i++){
 -if(iterator-pathdata.Types[i]  PathPointTypePathMarker){
 +if((iterator-pathdata.Types[i]  PathPointTypePathMarker) ||
 +   (i == iterator-pathdata.Count - 1)){
 *startIndex = iterator-marker_pos;
 if(iterator-marker_pos  0) (*startIndex)++;
 *endIndex   = iterator-marker_pos = i;
 diff --git a/dlls/gdiplus/tests/pathiterator.c 
 b/dlls/gdiplus/tests/pathiterator.c
 index 071c1d5..6498bb3 100644
 --- a/dlls/gdiplus/tests/pathiterator.c
 +++ b/dlls/gdiplus/tests/pathiterator.c
 @@ -114,7 +114,7 @@ static void test_nextmarker(void)
 GdipCreatePathIter(iter, path);
 stat = GdipPathIterNextMarker(iter, result, start, end);
 expect(Ok, stat);
 -expect(0, result);
 +if(stat == Ok) expect(TRUE, (result == 4)  (start == 0)  (end == 
 3));
 

 Why are you checking if stat == Ok?  You're linking what should be
 separate tests together.  You also need to put each of these checks
 into separate tests.  If the test fails, you have no idea (without
 debugging further) which one of those checks fails.  They're called
 unit tests for a reason.
   
I don't think so. If the call fails testing return value doesn't make 
any sense. In this case 'result' is uninitialized and remains 
uninitialized after a call if it fails (here I mean a native too). So 
why should we check something which has unpredictable value?
By the way first time I saw this here 
8fd6f0e26ae28f2ba4938e2fbcc4851f47baa53c..
 




Re: [2/3] gdiplus: fix GdipPathIterNextMarker behaviour on path without markers. fix tests.

2008-07-12 Thread James Hawkins
On Sat, Jul 12, 2008 at 12:37 PM, Nikolay Sivov [EMAIL PROTECTED] wrote:
 James Hawkins wrote:

 On Sat, Jul 12, 2008 at 11:56 AM, Nikolay Sivov [EMAIL PROTECTED]
 wrote:


 Changelog:
   -  Fix GdipPathIterNextMarker behaviour on path without markers. Make
 tests pass on native.

 ---
  dlls/gdiplus/pathiterator.c   |3 ++-
  dlls/gdiplus/tests/pathiterator.c |6 +++---
  2 files changed, 5 insertions(+), 4 deletions(-)

 diff --git a/dlls/gdiplus/pathiterator.c b/dlls/gdiplus/pathiterator.c
 index 55b0782..3d3b1dc 100644
 --- a/dlls/gdiplus/pathiterator.c
 +++ b/dlls/gdiplus/pathiterator.c
 @@ -140,7 +140,8 @@ GpStatus WINGDIPAPI
 GdipPathIterNextMarker(GpPathIterator* iterator, INT *result
/* first call could start with second point as all subsequent, cause
   path couldn't contain only one */
for(i = iterator-marker_pos + 1; i  iterator-pathdata.Count; i++){
 -if(iterator-pathdata.Types[i]  PathPointTypePathMarker){
 +if((iterator-pathdata.Types[i]  PathPointTypePathMarker) ||
 +   (i == iterator-pathdata.Count - 1)){
*startIndex = iterator-marker_pos;
if(iterator-marker_pos  0) (*startIndex)++;
*endIndex   = iterator-marker_pos = i;
 diff --git a/dlls/gdiplus/tests/pathiterator.c
 b/dlls/gdiplus/tests/pathiterator.c
 index 071c1d5..6498bb3 100644
 --- a/dlls/gdiplus/tests/pathiterator.c
 +++ b/dlls/gdiplus/tests/pathiterator.c
 @@ -114,7 +114,7 @@ static void test_nextmarker(void)
GdipCreatePathIter(iter, path);
stat = GdipPathIterNextMarker(iter, result, start, end);
expect(Ok, stat);
 -expect(0, result);
 +if(stat == Ok) expect(TRUE, (result == 4)  (start == 0)  (end ==
 3));


 Why are you checking if stat == Ok?  You're linking what should be
 separate tests together.  You also need to put each of these checks
 into separate tests.  If the test fails, you have no idea (without
 debugging further) which one of those checks fails.  They're called
 unit tests for a reason.


 I don't think so. If the call fails testing return value doesn't make any
 sense. In this case 'result' is uninitialized and remains uninitialized
 after a call if it fails (here I mean a native too). So why should we check
 something which has unpredictable value?
 By the way first time I saw this here
 8fd6f0e26ae28f2ba4938e2fbcc4851f47baa53c..


An API defines a unique output* for the set of all possible inputs.
When you write unit tests, you verify that the implementation of the
API conforms to the definition.  In the case of Wine, our definition
of the Win32 API is the test results from running the Wine test suite
in Windows.  While msdn is a good reference, it's not always correct
and we can't test our implementation against it.

In all the cases where you've added checks for (stat != Ok), stat does
equal Ok in Windows.  Thus, the definition of the API for those inputs
is that the functions return Ok.  If, for a hypothetical example, one
version of gdiplus did not return Ok, we would probably mark that as
broken.  That leads me to my next point.

You say you added the checks because it's wrong to check the value of
an uninitialized variable.  You are correct in that it is wrong to
check the value of an uninitialized variable.  Where you are mistaken
is that, by the definition of this API, none of these out variables
will be uninitialized in these cases.  One area where your tests are
lacking is that you don't control all of the input.  Even in the
failure case, you should initialize all out variables to some magic
value and then check the values of those parameters after the failed
call.  Either the values were unchanged, and thus still hold the magic
value, or they are set to some other value.  One bonus of this
practice is that, even if the test fails in Wine when it should
succeed, you're guaranteed to never read the value of an uninitialized
variable.

So to answer your question, there should be no unpredictable values in
a well-written test.

* or a unique set of acceptable outputs, e.g., multiple GetLastError values.

-- 
James Hawkins




Re: [2/3] gdiplus: fix GdipPathIterNextMarker behaviour on path without markers. fix tests.

2008-07-12 Thread Nikolay Sivov
James Hawkins wrote:
 On Sat, Jul 12, 2008 at 12:37 PM, Nikolay Sivov [EMAIL PROTECTED] wrote:
   
 James Hawkins wrote:
 
 On Sat, Jul 12, 2008 at 11:56 AM, Nikolay Sivov [EMAIL PROTECTED]
 wrote:

   
 Changelog:
   -  Fix GdipPathIterNextMarker behaviour on path without markers. Make
 tests pass on native.

 ---
  dlls/gdiplus/pathiterator.c   |3 ++-
  dlls/gdiplus/tests/pathiterator.c |6 +++---
  2 files changed, 5 insertions(+), 4 deletions(-)

 diff --git a/dlls/gdiplus/pathiterator.c b/dlls/gdiplus/pathiterator.c
 index 55b0782..3d3b1dc 100644
 --- a/dlls/gdiplus/pathiterator.c
 +++ b/dlls/gdiplus/pathiterator.c
 @@ -140,7 +140,8 @@ GpStatus WINGDIPAPI
 GdipPathIterNextMarker(GpPathIterator* iterator, INT *result
/* first call could start with second point as all subsequent, cause
   path couldn't contain only one */
for(i = iterator-marker_pos + 1; i  iterator-pathdata.Count; i++){
 -if(iterator-pathdata.Types[i]  PathPointTypePathMarker){
 +if((iterator-pathdata.Types[i]  PathPointTypePathMarker) ||
 +   (i == iterator-pathdata.Count - 1)){
*startIndex = iterator-marker_pos;
if(iterator-marker_pos  0) (*startIndex)++;
*endIndex   = iterator-marker_pos = i;
 diff --git a/dlls/gdiplus/tests/pathiterator.c
 b/dlls/gdiplus/tests/pathiterator.c
 index 071c1d5..6498bb3 100644
 --- a/dlls/gdiplus/tests/pathiterator.c
 +++ b/dlls/gdiplus/tests/pathiterator.c
 @@ -114,7 +114,7 @@ static void test_nextmarker(void)
GdipCreatePathIter(iter, path);
stat = GdipPathIterNextMarker(iter, result, start, end);
expect(Ok, stat);
 -expect(0, result);
 +if(stat == Ok) expect(TRUE, (result == 4)  (start == 0)  (end ==
 3));

 
 Why are you checking if stat == Ok?  You're linking what should be
 separate tests together.  You also need to put each of these checks
 into separate tests.  If the test fails, you have no idea (without
 debugging further) which one of those checks fails.  They're called
 unit tests for a reason.

   
 I don't think so. If the call fails testing return value doesn't make any
 sense. In this case 'result' is uninitialized and remains uninitialized
 after a call if it fails (here I mean a native too). So why should we check
 something which has unpredictable value?
 By the way first time I saw this here
 8fd6f0e26ae28f2ba4938e2fbcc4851f47baa53c..

 

 An API defines a unique output* for the set of all possible inputs.
 When you write unit tests, you verify that the implementation of the
 API conforms to the definition.  In the case of Wine, our definition
 of the Win32 API is the test results from running the Wine test suite
 in Windows.  While msdn is a good reference, it's not always correct
 and we can't test our implementation against it.
   
If you mean that an API's defined by a mapping of all possible inputs to 
a set of outputs I'm agreed.
 In all the cases where you've added checks for (stat != Ok), stat does
 equal Ok in Windows.  Thus, the definition of the API for those inputs
 is that the functions return Ok.  If, for a hypothetical example, one
 version of gdiplus did not return Ok, we would probably mark that as
 broken.  That leads me to my next point.

 You say you added the checks because it's wrong to check the value of
 an uninitialized variable.  You are correct in that it is wrong to
 check the value of an uninitialized variable.  Where you are mistaken
 is that, by the definition of this API, none of these out variables
 will be uninitialized in these cases.  One area where your tests are
 lacking is that you don't control all of the input.  Even in the
 failure case, you should initialize all out variables to some magic
 value and then check the values of those parameters after the failed
 call.  Either the values were unchanged, and thus still hold the magic
 value, or they are set to some other value.  One bonus of this
 practice is that, even if the test fails in Wine when it should
 succeed, you're guaranteed to never read the value of an uninitialized
 variable.
   
So you mean here that in this case testing return value should be 
unlinked to testing outputs, that these tests are  independent. Maybe it 
really helps when behaviour changes (API changes in fact) from version 
to version. So maybe it's the better way to split this and let it both 
test fail.
 So to answer your question, there should be no unpredictable values in
 a well-written test.

 * or a unique set of acceptable outputs, e.g., multiple GetLastError values.
Yes, I thought about some special 'magic' values for output arguments. 
Some deadbeef should be acceptable.
Thanks for comments I'll repost these fixes.