* Bug 16274 fixed: assert_checkequal() with Nan or void in containers 14/21514/4
Samuel GOUGEON [Mon, 29 Jun 2020 20:36:10 +0000 (22:36 +0200)]
  http://bugzilla.scilab.org/16274

Change-Id: Idc5058969b1fc3cd25aa69efe276a7b808df379d

scilab/CHANGES.md
scilab/modules/development_tools/help/en_US/assert/assert_checkequal.xml
scilab/modules/development_tools/help/ja_JP/assert/assert_checkequal.xml
scilab/modules/development_tools/help/ru_RU/assert/assert_checkequal.xml
scilab/modules/development_tools/macros/assert/assert_checkequal.sci
scilab/modules/development_tools/tests/unit_tests/assert/checkequal.tst

index 4bc08da..66aa23c 100644 (file)
@@ -276,6 +276,7 @@ Bug Fixes
 * [#15839](https://bugzilla.scilab.org/15839): `gsort`: the only sparse possible input were real or complex vectors, and only with the `g` method.
 * [#15842](https://bugzilla.scilab.org/15842): `unique` could not process 2D sparse matrices.
 * [#16106](https://bugzilla.scilab.org/16106): Xcos sciblk4 user-defined blocks did not handle opar and odstate/oz correctly.
+* [#16274](https://bugzilla.scilab.org/16274): assert_checkequal() did not considered equal matching Nan or void elements in (nested) containers.
 * [#16337](https://bugzilla.scilab.org/16337): The 3rd output of `[U,km,ku] = unique(..)` was not implemented.
 * [#16342](https://bugzilla.scilab.org/16342): `strcat()` was much slower in Scilab 6.0.2.
 * [#16350](https://bugzilla.scilab.org/16350): in if/while conditions, the empty sparse boolean was considered as TRUE.
index 8c625db..bd35853 100644 (file)
             Performs silently if <varname>computed</varname> and <varname>expected</varname> are equal.
         </para>
         <para>
-            If the type of both input arguments is 1 (i.e. a matrix of real or complex numbers),
-            we check that non-nan values are equal (matching Nan values are considered equal).
-        </para>
-        <para>
             For complex numbers: We compare first the real parts. In case of equality, we compare
             the imaginary parts.
         </para>
         <para>
+            Matching Nan values are always considered equal.
+        </para>
+        <para>
             <literal>1/%z</literal> and <literal>2/(2*%z)</literal> are not equal: For the time
             being, Scilab does not normalize equivalent rationals.
         </para>
         <para>
-            In two lists, matching void elements are considered equal.
+            In containers, matching <literal>void</literal> elements are considered equal.
         </para>
         <para>
             If the comparison shows that computed is equal to expected,
@@ -172,6 +171,10 @@ assert_checkequal: Assertion failed: expected= lib@SCI\modules\core\macros\  whi
 ]]></screen>
     </refsection>
     <refsection>
+        <title>Bibliography</title>
+        <para>"Automated Software Testing for Matlab", Steven Eddins, 2009</para>
+    </refsection>
+    <refsection>
         <title>History</title>
         <revhistory>
             <revision>
@@ -202,10 +205,12 @@ assert_checkequal: Assertion failed: expected= lib@SCI\modules\core\macros\  whi
                   </itemizedlist>
                 </revdescription>
             </revision>
+            <revision>
+                <revnumber>6.1.1</revnumber>
+                <revdescription>
+                    Matching NaN or void elements in simple or nested containers are now considered equal.
+                </revdescription>
+            </revision>
         </revhistory>
     </refsection>
-    <refsection>
-        <title>Bibliography</title>
-        <para>"Automated Software Testing for Matlab", Steven Eddins, 2009</para>
-    </refsection>
 </refentry>
index 1a9eeb2..5454b86 100644 (file)
             computedとexpectedが等しい場合,そのまま実行されます.
         </para>
         <para>
-            入力引数の型が共に1 (すなわち実数行列)の場合,
-            nan以外の値が等しいことが確認されます (matching Nan values are considered equal).
+            For complex numbers: まず実部を確認し,それが等しい場合に虚部を確認します.
         </para>
         <para>
-            For complex numbers: まず実部を確認し,それが等しい場合に虚部を確認します.
+            Matching Nan values are always considered equal.
         </para>
         <para>
             <literal>1/%z</literal> and <literal>2/(2*%z)</literal> are not equal: For the time
             being, Scilab does not normalize equivalent rationals.
         </para>
         <para>
-            In two lists, matching void elements are considered equal.
+             In containers, matching <literal>void</literal> elements are considered equal.
         </para>
         <para>
             比較がcomputedがexpectedに等しくないことを示す場合,
@@ -176,6 +175,10 @@ assert_checkequal: Assertion failed: expected= lib@SCI\modules\core\macros\  whi
 ]]></screen>
     </refsection>
     <refsection>
+        <title>参考文献</title>
+        <para>"Automated Software Testing for Matlab", Steven Eddins, 2009</para>
+    </refsection>
+    <refsection>
         <title>履歴</title>
         <revhistory>
             <revision>
@@ -206,10 +209,12 @@ assert_checkequal: Assertion failed: expected= lib@SCI\modules\core\macros\  whi
                    </itemizedlist>
                 </revdescription>
             </revision>
+            <revision>
+                <revnumber>6.1.1</revnumber>
+                <revdescription>
+                    Matching NaN or void elements in simple or nested containers are now considered equal.
+                </revdescription>
+            </revision>
         </revhistory>
     </refsection>
-    <refsection>
-        <title>参考文献</title>
-        <para>"Automated Software Testing for Matlab", Steven Eddins, 2009</para>
-    </refsection>
 </refentry>
index b547c3e..9263491 100644 (file)
@@ -28,7 +28,6 @@
             assert_checkequal ( computed , expected )
             flag = assert_checkequal ( computed , expected )
             [flag,errmsg] = assert_checkequal ( computed , expected )
-
         </synopsis>
     </refsynopsisdiv>
     <refsection>
             Работает молча, если <varname>computed</varname> и <varname>expected</varname> равны.
         </para>
         <para>
-            Если тип обоих входных аргументов равен 1 (т.е. матрица вещественных или комплексных
-            чисел), то мы проверяем, что не-Nan значения равны (совпадающие Nan-значения
-            считаются равными).
-        </para>
-        <para>
             Для комплексных чисел: мы сравниваем сначала вещественные части. В случае равенства
             мы сравниваем мнимые части.
         </para>
         <para>
+            Сопоставляемые значения <literal>Nan</literal> всегда считаются равными.
+        </para>
+        <para>
             <literal>1/%z</literal> и <literal>2/(2*%z)</literal> не равны: для времени Scilab
             не нормирует эквивалентные рациональные значения.
         </para>
         <para>
-            В двух списках совпадающие пустые элементы считаются равными.
+            В контейнерах, сопоставляемые элементы <literal>void</literal> считаются равными.
         </para>
         <para>
             Если сравнение показывает, что вычисленное равно ожидаемому, то
@@ -183,6 +180,10 @@ assert_checkequal: Assertion failed: expected= lib@SCI\modules\core\macros\  whi
 ]]></screen>
     </refsection>
     <refsection>
+        <title>Литература</title>
+        <para>"Automated Software Testing for Matlab", Steven Eddins, 2009</para>
+    </refsection>
+    <refsection>
         <title>История</title>
         <revhistory>
             <revision>
@@ -195,28 +196,32 @@ assert_checkequal: Assertion failed: expected= lib@SCI\modules\core\macros\  whi
                 <revdescription>
                     <itemizedlist>
                       <listitem>
-                          The comparison of two implicit lists, Scilab functions, Scilab libraries,
-                          built-in functions or graphic handles is now always possible and properly
-                          done.
+                          Сравнение двух неявных списков, Scilab-функций, Scilab-библиотек,
+                          встроенных функций или графических дескрипторов теперь всегда возможны и
+                          и должным образом выполняются.
                       </listitem>
                       <listitem>
-                          In two lists, void and Nan elements are now supported, and matching ones
-                          are considered as equal.
+                          В двух списках теперь поддерживаются элементы void и Nan и соответствующие
+                          элементы рассматриваются как равные.
                       </listitem>
                       <listitem>
-                          Nan are now supported in input sparse matrices and are considered as equal.
+                          Nan теперь поддерживаются во входных разрежённых матрицах и считаются
+                          равными.
                       </listitem>
                       <listitem>
-                          When the test fails while inputs are arrays, the message now indicates
-                          the index of the first mismatching element.
+                          При провалах тестов, когда на входе массивы, сообщение теперь указывает
+                          индекс первого несовпадающего элемента.
                       </listitem>
                    </itemizedlist>
                 </revdescription>
             </revision>
+            <revision>
+                <revnumber>6.1.1</revnumber>
+                <revdescription>
+                    Соответствющие элементы NaN или void в простых или вложенных контейнерах теперь
+                    считаются равными.
+                </revdescription>
+            </revision>
         </revhistory>
     </refsection>
-    <refsection>
-        <title>Литература</title>
-        <para>"Automated Software Testing for Matlab", Steven Eddins, 2009</para>
-    </refsection>
 </refentry>
index 5013ea4..bfa62e9 100644 (file)
@@ -1,7 +1,7 @@
 // Copyright (C) 2008-2009 - INRIA - Michael Baudin
 // Copyright (C) 2010 - 2011 - DIGITEO - Michael Baudin
 // Copyright (C) 2012 - 2016 - Scilab Enterprises
-// Copyright (C) 2019 - Samuel GOUGEON
+// Copyright (C) 2019 - 2020 - Samuel GOUGEON
 //
 // This file is hereby licensed under the terms of the GNU GPL v2.0,
 // pursuant to article 5.3.4 of the CeCILL v.2.1.
 // For more information, see the COPYING file which you should have received
 // along with this program.
 
-function [flag,errmsg] = assert_checkequal ( computed , expected )
+function [flag, errmsg] = assert_checkequal(computed, expected)
     //  Check that computed and expected are equal.
-    [lhs,rhs]=argn()
+    [lhs,rhs] = argn()
     if ( rhs <> 2 ) then
-        errmsg = sprintf ( gettext ( "%s: Wrong number of input arguments: %d expected.\n") , "assert_checkequal" , 2 )
-        error(errmsg)
+        errmsg = gettext("%s: Wrong number of input arguments: %d expected.\n")
+        error(msprintf(errmsg, "assert_checkequal", 2))
     end
 
     // Check types of variables
     if ( typeof(computed) <> typeof(expected) ) then
-        errmsg = sprintf ( gettext ( "%s: Incompatible input arguments #%d and #%d: Same types expected.\n" ) , "assert_checkequal" , 1 , 2 )
-        error(errmsg)
-   end
+        errmsg = gettext("%s: Incompatible input arguments #%d and #%d: Same types expected.\n")
+        error(msprintf(errmsg, "assert_checkequal", 1, 2))
+    end
 
     //
     // Check sizes of variables
-    if ( or(type(computed)==[16 17]) ) then
+    if type(computed)==15 then
         ncom = length(computed)
+        nexp = length(expected)
+    elseif or(typeof(computed)==["ce" "st"])
+        ncom = size(computed)
+        nexp = size(expected)
     else
         try
             ncom = size(computed)
+            nexp = size(expected)
         catch   // non-sizeable objects: 1:$, iolib, sin, sind, etc
             ncom = -2
-        end
-    end
-    if ( or(type(expected)==[16 17]) ) then
-        nexp = length(expected)
-    else
-        try
-            nexp = size(expected)
-        catch
             nexp = -2
         end
     end
     if ( or(ncom <> nexp) ) then
-        errmsg = sprintf ( gettext ( "%s: Incompatible input arguments #%d and #%d: Same sizes expected.\n") , "assert_checkequal" , 1 , 2 )
+        errmsg = msprintf(gettext ( "%s: Incompatible input arguments #%d and #%d: Same sizes expected.\n"), "assert_checkequal", 1 , 2)
         error(errmsg)
     end
 
@@ -54,11 +51,11 @@ function [flag,errmsg] = assert_checkequal ( computed , expected )
         cisreal = isreal(computed)
         eisreal = isreal(expected)
         if ( cisreal & ~eisreal ) then
-            errmsg = sprintf ( gettext ( "%s: Computed is real, but expected is complex.") , "assert_checkequal" )
+            errmsg = msprintf(gettext("%s: Computed is real, but expected is complex."), "assert_checkequal")
             error(errmsg)
         end
         if ( ~cisreal & eisreal ) then
-            errmsg = sprintf ( gettext ( "%s: Computed is complex, but expected is real.") , "assert_checkequal" )
+            errmsg = msprintf(gettext("%s: Computed is complex, but expected is real."), "assert_checkequal")
             error(errmsg)
         end
         if cisreal & eisreal then
@@ -69,7 +66,7 @@ function [flag,errmsg] = assert_checkequal ( computed , expected )
                 [flag ,k] = comparedoubles ( imag(computed) , imag(expected) )
             end
         end
-        // k is the index of the first discrepancy (or [] is none)
+        // k is the index of the first discrepancy (or [] if none)
 
     elseif or(typeof(computed)==["implicitlist" "fptr" "function"])
                                     // http://bugzilla.scilab.org/16104 C) D) E)
@@ -109,32 +106,11 @@ function [flag,errmsg] = assert_checkequal ( computed , expected )
         end
         return
 
-    elseif type(computed)==15   // Simple lists
-        b = computed==expected
-        flag = and(b)
-        if ~flag
-            // computed<>expected can't be simply used due to // http://bugzilla.scilab.org/15293
-            flag = %t
-            for i = find(~b)
-                tc = type(computed(i))
-                te = type(expected(i))
-                if tc==0 & te==0
-                    continue
-                elseif tc<>0 & te<>0 & isnan(computed(i)) & isnan(expected(i))
-                    continue
-                else
-                    flag = %f
-                    k = i
-                    if tc==0
-                        computed(k) = "(void)"
-                    end
-                    if te==0
-                        expected(k) = "(void)"
-                    end
-                    break
-                end
-            end
-        end
+    elseif or(type(computed)==[15 16 17 ])
+        [flag, k] = compareContainers(computed , expected)
+
+    elseif type(computed) == 0
+        flag = %t
 
     else
         b = and(computed == expected)
@@ -150,28 +126,48 @@ function [flag,errmsg] = assert_checkequal ( computed , expected )
     else
         // Sets the message according to the type and size of the pair:
         if or(typeof(expected) == ["sparse", "boolean sparse"])
-            e = full(expected(k))
-            c = full(computed(k))
-        elseif isdef("k","l")
-            e = expected(k)
-            c = computed(k)
+            estr = string(full(expected(k)))
         else
-            try
-            e = expected(1)
-            c = computed(1)
-            catch
-            e = expected
-            c = computed
+            s = "expected(1)"
+            if isdef("k","l") & k <> []
+                s = "expected(k)"
+            end
+            err = execstr("e = "+s+"; t = type("+s+")", "errcatch")
+            if err <> 0
+                e = expected
+                t = type(e)
+            end
+            if t==0
+                estr = "(void)"
+            elseif t==9
+                estr = msprintf("%s(uid:%d)", e.type, e.uid)
+            else
+                estr = string(e)
             end
         end
-        if type(computed)==9
-            estr = msprintf("%s(uid:%d)", e.type, e.uid)
-            cstr = msprintf("%s(uid:%d)", c.type, c.uid)
+        //
+        if or(typeof(computed) == ["sparse", "boolean sparse"])
+            cstr = full(computed(k))
         else
-            estr = string(e)
-            cstr = string(c)
+            s = "computed(1)"
+            if isdef("k","l") & k <> []
+                s = "computed(k)"
+            end
+            err = execstr("c = "+s+"; t = type("+s+")", "errcatch")
+            if err <> 0
+                c = computed
+                t = type(c)
+            end
+            if t==0
+                cstr = "(void)"
+            elseif t==9
+                cstr = msprintf("%s(uid:%d)", c.type, c.uid)
+            else
+                cstr = string(c)
+            end
         end
-        if isdef("k","l") & length(computed)>1
+        //
+        if isdef("k","l") & k <> [] & length(computed)>1
             estr = msprintf(_("expected(%d)= "),k) + estr
             cstr = msprintf(_("computed(%d)= "),k) + cstr
         else
@@ -203,3 +199,95 @@ function [flag, k] = comparedoubles ( computed , expected )
     k = find(expected<>computed,1);
     flag = k==[];
 endfunction
+// ---------------------------------------------------------------------------
+function [areEqual, k] = compareContainers(computed , expected)
+    // http://bugzilla.scilab.org/15293
+    // http://bugzilla.scilab.org/16274
+    tc = typeof(computed)
+    te = typeof(expected)
+    k = []
+    areEqual = tc == te
+    if ~areEqual
+        return
+    end
+    if or(type(computed)==[1 5])
+        if and(computed == expected)
+            return
+        end
+        if isreal(computed) <> isreal(expected)
+            areEqual = %f
+            return
+        end
+        [areEqual, k] = comparedoubles(real(computed), real(expected))
+        if areEqual
+            [areEqual, k] = comparedoubles(imag(computed), imag(expected))
+        end
+
+    elseif or(type(computed)==[16 17]) then
+        if and(computed == expected)
+            return
+        end
+        if or(size(computed) <> size(expected)) then
+            areEqual = %f
+            return
+        end
+        fc = fieldnames(computed)
+        areEqual = and(fc == fieldnames(expected))
+        if ~areEqual
+            return
+        end
+        if fc <> []
+            for f = fc'
+                [areEqual, k] = compareContainers(computed(f) , expected(f))
+                if ~areEqual
+                    break
+                end
+            end
+        elseif tc=="ce"
+            [areEqual, k] = compareContainers(computed{:} , expected{:})
+            if ~areEqual
+                break
+            end
+        end
+
+    elseif type(computed)==14   // Libraries
+        areEqual = and(string(computed)==string(expected))
+
+    elseif tc=="list"
+        if and(computed == expected)
+            return
+        end
+        if length(computed) <> length(expected)
+            areEqual = %f
+            return
+        end
+        dfc = definedfields(computed)
+        dfe = definedfields(expected)
+        if or(dfc <> dfe)
+            if length(dfc)==length(dfe)
+                k = find(dfc <> dfe, 1)
+            else
+                tmp = union(setdiff(dfc, dfe), setdiff(dfe, dfc))
+                k = tmp(find(tmp,1))
+            end
+            areEqual = %f
+            return
+        end
+        for k = dfc
+            areEqual = compareContainers(computed(k) , expected(k))
+            if ~areEqual
+                break
+            end
+        end
+
+    elseif (tc=="void" & te=="void")
+        return
+
+    elseif type(computed) <> 0
+        b = and(computed == expected)
+        areEqual = b || isequal(computed, expected)
+        if ~areEqual & ~b
+            k = find(computed <> expected, 1);
+        end
+    end
+endfunction
index a16443b..0681d5e 100644 (file)
@@ -135,6 +135,8 @@ s = list(1,,list(2,,4));
 assert_checkequal(s, s);
 s = list("foo",2);
 assert_checkequal(s, s);
+s = list(1,list(,%nan,,2),,%nan,1);
+assert_checkequal(s, s);
 ierr = execstr("assert_checkequal(list(2,,7), list(2,%F,8))","errcatch");
 MY_assert_equal(ierr, 10000);
 errmsg = lasterror();
@@ -144,6 +146,10 @@ refmsg = msprintf(refmsg, "assert_checkequal", ..
     msprintf(_("computed(%d)= "),2) + "(void)");
 MY_assert_equal( errmsg , refmsg );
 
+// void
+// ----
+assert_checkequal(list(,3)(1), list(,3)(1));
+
 // Mlist
 // -----
 s = mlist(["V","name","value"],["a","b";"c" "d"],[1 2; 3 4]);
@@ -153,6 +159,13 @@ assert_checkequal(s, s);
 // -----
 s = tlist(["V","name","value"],["a","b";"c" "d"],[1 2; 3 4]);
 assert_checkequal(s, s);
+
+// Cells
+// -----
+assert_checkequal({}, {});
+o = {1, %f, %z ; "abc" %nan list(,3)};
+assert_checkequal(o, o);
+assert_checkequal({%nan}, {%nan});  // http://bugzilla.scilab.org/16274
 //
 // Polynomial
 // ----------
@@ -170,7 +183,7 @@ t = s;
 s(1)=12;
 instr="assert_checkequal(s, t)";
 ierr=execstr(instr,"errcatch");
-MY_assert_equal(ierr, 10000);
+MY_assert_equal(ierr, 999);
 
 //
 // Boolean
@@ -187,7 +200,7 @@ assert_checkequal(s, t);
 s(1)=%f;
 instr="assert_checkequal(s, t)";
 ierr=execstr(instr,"errcatch");
-MY_assert_equal(ierr, 10000);
+MY_assert_equal(ierr, 999);
 
 //
 // Integer 8