Repository.mk                                 |    1 
 desktop/CppunitTest_desktop_lib.mk            |    1 
 scp2/source/ooo/directory_ooo.scp             |    5 
 wizards/Module_wizards.mk                     |    1 
 wizards/Package_sfunittests.mk                |   30 
 wizards/source/configshare/dialog.xlc         |    1 
 wizards/source/configshare/script.xlc         |    1 
 wizards/source/scriptforge/SF_Exception.xba   |   10 
 wizards/source/scriptforge/SF_Root.xba        |   15 
 wizards/source/scriptforge/SF_Services.xba    |    1 
 wizards/source/scriptforge/SF_Utils.xba       |    7 
 wizards/source/scriptforge/po/ScriptForge.pot |   22 
 wizards/source/scriptforge/po/en.po           |   22 
 wizards/source/sfunittests/SF_Register.xba    |  202 ++
 wizards/source/sfunittests/SF_UnitTest.xba    | 1820 ++++++++++++++++++++++++++
 wizards/source/sfunittests/__License.xba      |   26 
 wizards/source/sfunittests/dialog.xlb         |    3 
 wizards/source/sfunittests/script.xlb         |    7 
 18 files changed, 2171 insertions(+), 4 deletions(-)

New commits:
commit 14c7bc1c90d671743c2f25b6958bb54f03140597
Author:     Jean-Pierre Ledure <[email protected]>
AuthorDate: Fri Jun 3 17:51:57 2022 +0200
Commit:     Jean-Pierre Ledure <[email protected]>
CommitDate: Sat Jun 4 12:08:36 2022 +0200

    ScriptForge - New 'UnitTest' service for Basic
    
    The "UnitTest" service is implemented as a new
    Basic library called 'SFUnitTests'.
    
    ScriptForge unit tests (SF_UnitTest class module)
    ======================
    Class providing a framework to execute and check sets of unit tests.
    
    The UnitTest unit testing framework was originally
    inspired by unittest.py in Python
    and has a similar flavor as major unit testing
    frameworks in other languages.
    
    It supports
    - test automation
    - sharing of setupand shutdown code
    - aggregation of tests into collections.
    
    Both the
    - code describing the unit tests
    - code to be tested
    must be written exclusively in Basic
    (the code might call functions written in other languages).
    The code to be tested may be released as an extension.
    It does not need to make use of ScriptForge services.
    
    The test reporting device is the Console.
    
    Definitions:
    - Test Case: each test case is a Basic Sub.
    - Test Suite: a collection of test cases stored in 1 Basic module.
    - Unit test: a set of test suites stored in 1 library.
    
    Two modes:
    - the normal mode ("full mode"), using test suites and test cases
      The UnitTest service is passed as argument to each test case.
    - the "simple mode" limited to the use of the Assert...() methods.
    
    Service invocation examples:
    - In full mode, the service creation is external to test cases
            Dim myUnitTest As Variant
            myUnitTest = CreateScriptService("UnitTest", ThisComponent, "Tests")
                '    Test code is in the library "Tests"
                '    located in the current document
    - In simple mode, the service creation is internal to every test case
            Dim myUnitTest As Variant
            myUnitTest = CreateScriptService("UnitTest")
            With myUnitTest
                If Not .AssertTrue(...) Then ...
                '    ...
                .Dispose()
            End With
    
    Error handling
    To support the debugging of the tested code, the UnitTest service, in cases 
of
    - assertion failure
    - Basic run-time error in the tested code
    - Basic run-time error in the testing code (the unit tests)
    will comment the error location and description in a message box and in the 
console log,
    providing every test case (in either mode) implements an error handler
    containing at least a call to the ReportError() method.
    
    Change-Id: I9d9b889b148f172cd868af455493c8c696d1e953
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135365
    Tested-by: Jean-Pierre Ledure <[email protected]>
    Tested-by: Jenkins
    Reviewed-by: Jean-Pierre Ledure <[email protected]>

diff --git a/Repository.mk b/Repository.mk
index 5532b993dfde..4004cbe142df 100644
--- a/Repository.mk
+++ b/Repository.mk
@@ -1002,6 +1002,7 @@ $(eval $(call 
gb_Helper_register_packages_for_install,ooo,\
        wizards_basicsrvsfdatabases \
        wizards_basicsrvsfdialogs \
        wizards_basicsrvsfdocuments \
+       wizards_basicsrvsfunittests \
        wizards_basicsrvsfwidgets \
        wizards_basicsrvstandard \
        wizards_basicsrvtemplate \
diff --git a/desktop/CppunitTest_desktop_lib.mk 
b/desktop/CppunitTest_desktop_lib.mk
index 61d5cb1f31c5..d8f58cac18da 100644
--- a/desktop/CppunitTest_desktop_lib.mk
+++ b/desktop/CppunitTest_desktop_lib.mk
@@ -75,6 +75,7 @@ $(eval $(call gb_CppunitTest_use_packages,desktop_lib, \
     wizards_basicsrvsfdatabases \
     wizards_basicsrvsfdialogs \
     wizards_basicsrvsfdocuments \
+    wizards_basicsrvsfunittests \
     wizards_basicsrvsfwidgets \
     wizards_basicsrvtemplate \
     wizards_basicsrvtools \
diff --git a/scp2/source/ooo/directory_ooo.scp 
b/scp2/source/ooo/directory_ooo.scp
index 66c895575a7f..71bc2f2f76eb 100644
--- a/scp2/source/ooo/directory_ooo.scp
+++ b/scp2/source/ooo/directory_ooo.scp
@@ -285,6 +285,11 @@ Directory gid_Dir_Basic_SFDocuments
     DosName = "SFDocuments";
 End
 
+Directory gid_Dir_Basic_SFUnitTests
+    ParentID = gid_Dir_Basic;
+    DosName = "SFUnitTests";
+End
+
 Directory gid_Dir_Basic_SFWidgets
     ParentID = gid_Dir_Basic;
     DosName = "SFWidgets";
diff --git a/wizards/Module_wizards.mk b/wizards/Module_wizards.mk
index 14757e57bb10..580eafcdea29 100644
--- a/wizards/Module_wizards.mk
+++ b/wizards/Module_wizards.mk
@@ -33,6 +33,7 @@ $(eval $(call gb_Module_add_targets,wizards,\
        Package_sfdatabases \
        Package_sfdialogs \
        Package_sfdocuments \
+       Package_sfunittests \
        Package_sfwidgets \
        Package_standard \
        Package_template \
diff --git a/wizards/Package_sfunittests.mk b/wizards/Package_sfunittests.mk
new file mode 100644
index 000000000000..54b50e016e5a
--- /dev/null
+++ b/wizards/Package_sfunittests.mk
@@ -0,0 +1,30 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This file incorporates work covered by the following license notice:
+#
+#   Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements. See the NOTICE file distributed
+#   with this work for additional information regarding copyright
+#   ownership. The ASF licenses this file to you under the Apache
+#   License, Version 2.0 (the "License"); you may not use this file
+#   except in compliance with the License. You may obtain a copy of
+#   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+
+$(eval $(call 
gb_Package_Package,wizards_basicsrvsfunittests,$(SRCDIR)/wizards/source/sfunittests))
+
+$(eval $(call 
gb_Package_add_files,wizards_basicsrvsfunittests,$(LIBO_SHARE_FOLDER)/basic/SFUnitTests,\
+       SF_Register.xba \
+       SF_UnitTest.xba \
+       __License.xba \
+       dialog.xlb \
+       script.xlb \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/wizards/source/configshare/dialog.xlc 
b/wizards/source/configshare/dialog.xlc
index 8db62f073800..2849d7a9b79e 100644
--- a/wizards/source/configshare/dialog.xlc
+++ b/wizards/source/configshare/dialog.xlc
@@ -14,5 +14,6 @@
  <library:library library:name="SFDatabases" 
xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/SFDatabases/dialog.xlb/" 
xlink:type="simple" library:link="true" library:readonly="false"/>
  <library:library library:name="SFDialogs" 
xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/SFDialogs/dialog.xlb/" 
xlink:type="simple" library:link="true" library:readonly="false"/>
  <library:library library:name="SFDocuments" 
xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/SFDocuments/dialog.xlb/" 
xlink:type="simple" library:link="true" library:readonly="false"/>
+ <library:library library:name="SFUnitTests" 
xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/SFUnitTests/dialog.xlb/" 
xlink:type="simple" library:link="true" library:readonly="false"/>
  <library:library library:name="SFWidgets" 
xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/SFWidgets/dialog.xlb/" 
xlink:type="simple" library:link="true" library:readonly="false"/>
  </library:libraries>
diff --git a/wizards/source/configshare/script.xlc 
b/wizards/source/configshare/script.xlc
index d1de5ea4f948..ff05ff37b026 100644
--- a/wizards/source/configshare/script.xlc
+++ b/wizards/source/configshare/script.xlc
@@ -14,5 +14,6 @@
  <library:library library:name="SFDatabases" 
xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/SFDatabases/script.xlb/" 
xlink:type="simple" library:link="true" library:readonly="false"/>
  <library:library library:name="SFDialogs" 
xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/SFDialogs/script.xlb/" 
xlink:type="simple" library:link="true" library:readonly="false"/>
  <library:library library:name="SFDocuments" 
xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/SFDocuments/script.xlb/" 
xlink:type="simple" library:link="true" library:readonly="false"/>
+ <library:library library:name="SFUnitTests" 
xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/SFUnitTests/script.xlb/" 
xlink:type="simple" library:link="true" library:readonly="false"/>
  <library:library library:name="SFWidgets" 
xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/SFWidgets/script.xlb/" 
xlink:type="simple" library:link="true" library:readonly="false"/>
 </library:libraries>
diff --git a/wizards/source/scriptforge/SF_Exception.xba 
b/wizards/source/scriptforge/SF_Exception.xba
index aeac2fb91aab..11e97b02b753 100644
--- a/wizards/source/scriptforge/SF_Exception.xba
+++ b/wizards/source/scriptforge/SF_Exception.xba
@@ -133,6 +133,10 @@ Const SQLSYNTAXERROR                       =       
&quot;SQLSYNTAXERROR&quot;
 &apos; Python
 Const PYTHONSHELLERROR                 =       &quot;PYTHONSHELLERROR&quot;
 
+&apos; SF_UnitTest
+Const UNITTESTLIBRARYERROR             =       &quot;UNITTESTLIBRARYERROR&quot;
+Const UNITTESTMETHODERROR              =       &quot;UNITTESTMETHODERROR&quot;
+
 REM ============================================================= PRIVATE 
MEMBERS
 
 &apos; User defined errors
@@ -1025,6 +1029,12 @@ Try:
                        Case PYTHONSHELLERROR   &apos;  
SF_Exception.PythonShell (Python only)
                                sMessage = sLocation _
                                        &amp; &quot;\n&quot; &amp; 
&quot;\n&quot; &amp; .GetText(&quot;PYTHONSHELL&quot;)
+                       Case UNITTESTLIBRARYERROR       &apos;  
SFUnitTests._NewUnitTest(LibraryName)
+                               sMessage = sLocation _
+                                       &amp; &quot;\n&quot; &amp; 
&quot;\n&quot; &amp; .GetText(&quot;UNITTESTLIBRARY&quot;, pvArgs(0))
+                       Case UNITTESTMETHODERROR        &apos;  
SFUnitTests.SF_UnitTest(Method)
+                               sMessage = sLocation _
+                                       &amp; &quot;\n&quot; &amp; 
&quot;\n&quot; &amp; .GetText(&quot;UNITTESTMETHOD&quot;, pvArgs(0))
                        Case Else
                End Select
        End With
diff --git a/wizards/source/scriptforge/SF_Root.xba 
b/wizards/source/scriptforge/SF_Root.xba
index f0d81252469e..4db0efb42c1d 100644
--- a/wizards/source/scriptforge/SF_Root.xba
+++ b/wizards/source/scriptforge/SF_Root.xba
@@ -1012,6 +1012,21 @@ Try:
                                                , Comment :=    
&quot;SF_Exception.PythonShell error message&quot; _
                                                                        &amp;   
&quot;APSO: to leave unchanged&quot; _
                                        )
+       &apos;  SFUnitTests._NewUnitTest
+                       .AddText(       Context := &quot;UNITTESTLIBRARY&quot; _
+                                               , MsgId := &quot;The requested 
library could not be located.\n&quot; _
+                                                                       &amp; 
&quot;The UnitTest service has not been initialized.\n\n&quot; _
+                                                                       &amp; 
&quot;Library name : « %1 »&quot; _
+                                               , Comment :=    
&quot;SFUnitTest could not locate the library gven as argument\n&quot; _
+                                                                       &amp;   
&quot;%1: The name of the library&quot; _
+                                       )
+       &apos;  SFUnitTests.SF_UnitTest
+                       .AddText(       Context := &quot;UNITTESTMETHOD&quot; _
+                                               , MsgId := &quot;The method 
&apos;%1&apos; is unexpected in the current context.\n&quot; _
+                                                                       &amp; 
&quot;The UnitTest service cannot proceed further with the on-going test.&quot; 
_
+                                               , Comment :=    
&quot;SFUnitTest finds a RunTest() call in a inappropriate location\n&quot; _
+                                                                       &amp;   
&quot;%1: The name of a method&quot; _
+                                       )
                End With
        End If
 
diff --git a/wizards/source/scriptforge/SF_Services.xba 
b/wizards/source/scriptforge/SF_Services.xba
index a2ab63828819..627dc4d2e8fe 100644
--- a/wizards/source/scriptforge/SF_Services.xba
+++ b/wizards/source/scriptforge/SF_Services.xba
@@ -130,6 +130,7 @@ Try:
                                                                                
                                sLibrary = &quot;SFDocuments&quot;
                        Case &quot;dialog&quot;, &quot;dialogevent&quot;        
                :       sLibrary = &quot;SFDialogs&quot;
                        Case &quot;database&quot;                               
                        :       sLibrary = &quot;SFDatabases&quot;
+                       Case &quot;unittest&quot;                               
                        :       sLibrary = &quot;SFUnitTests&quot;
                        Case &quot;menu&quot;, &quot;popupmenu&quot;            
                :       sLibrary = &quot;SFWidgets&quot;
                        Case Else
                End Select
diff --git a/wizards/source/scriptforge/SF_Utils.xba 
b/wizards/source/scriptforge/SF_Utils.xba
index e26cca66a776..91b703c46431 100644
--- a/wizards/source/scriptforge/SF_Utils.xba
+++ b/wizards/source/scriptforge/SF_Utils.xba
@@ -51,8 +51,9 @@ Global Const  V_SFOBJECT              = 103   &apos;          
                                                                                
        ScriptForge object: has Object
 Global Const   V_BASICOBJECT   = 104   &apos;                                  
                                                                User Basic 
object
 
 Type _ObjectDescriptor                                 &apos; Returned by the 
_VarTypeObj() method
-       iVarType        As Integer                              &apos; One of 
the V_NOTHING, V_xxxOBJECT constants
-       sObjectType     As String                               &apos; Either 
&quot;&quot; or &quot;com.sun.star...&quot; or a ScriptForge object type (ex. 
&quot;SF_SESSION&quot; or &quot;DICTIONARY&quot;)
+       iVarType                As Integer                      &apos; One of 
the V_NOTHING, V_xxxOBJECT constants
+       sObjectType             As String                       &apos; Either 
&quot;&quot; or &quot;com.sun.star...&quot; or a ScriptForge object type (ex. 
&quot;SF_SESSION&quot; or &quot;DICTIONARY&quot;)
+       sServiceName    As String                       &apos; Either 
&quot;&quot; or the service name of a ScriptForge object type (ex. 
&quot;ScriptForge.Exception&quot;-
 End Type
 
 REM ================================================================== 
EXCEPTIONS
@@ -1065,6 +1066,7 @@ Try:
        With oObjDesc
                .iVarType = VarType(pvValue)
                .sObjectType = &quot;&quot;
+               .sServiceName = &quot;&quot;
                bUno = False
                If .iVarType = V_OBJECT Then
                        If IsNull(pvValue) Then
@@ -1089,6 +1091,7 @@ Try:
                                        bUno = False
                                        &apos;  Try if the Basic object has an 
ObjectType property
                                        .sObjectType = oValue.ObjectType
+                                       .sServiceName = oValue.ServiceName
                                End If
                                &apos;  Derive the return value from the object 
type
                                Select Case True
diff --git a/wizards/source/scriptforge/po/ScriptForge.pot 
b/wizards/source/scriptforge/po/ScriptForge.pot
index b1727527da58..248d800c017c 100644
--- a/wizards/source/scriptforge/po/ScriptForge.pot
+++ b/wizards/source/scriptforge/po/ScriptForge.pot
@@ -14,7 +14,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: 
https://bugs.libreoffice.org/enter_bug.cgi?product=LibreOffice&bug_status=UNCONFIRMED&component=UI\n";
-"POT-Creation-Date: 2022-03-09 14:52:15\n"
+"POT-Creation-Date: 2022-05-04 18:07:20\n"
 "PO-Revision-Date: YYYY-MM-DD HH:MM:SS\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <EMAIL@ADDRESS>\n"
@@ -952,4 +952,24 @@ msgctxt "PYTHONSHELL"
 msgid  ""
 "The APSO extension could not be located in your LibreOffice "
 "installation."
+msgstr ""
+
+#. SFUnitTest could not locate the library gven as argument
+#. %1: The name of the library
+#, kde-format
+msgctxt "UNITTESTLIBRARY"
+msgid  ""
+"The requested library could not be located.\n"
+"The UnitTest service has not been initialized.\n"
+"\n"
+"Library name : « %1 »"
+msgstr ""
+
+#. SFUnitTest finds a RunTest() call in a inappropriate location
+#. %1: The name of a method
+#, kde-format
+msgctxt "UNITTESTMETHOD"
+msgid  ""
+"The method '%1' is unexpected in the current context.\n"
+"The UnitTest service cannot proceed further with the on-going test."
 msgstr ""
\ No newline at end of file
diff --git a/wizards/source/scriptforge/po/en.po 
b/wizards/source/scriptforge/po/en.po
index b1727527da58..248d800c017c 100644
--- a/wizards/source/scriptforge/po/en.po
+++ b/wizards/source/scriptforge/po/en.po
@@ -14,7 +14,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: 
https://bugs.libreoffice.org/enter_bug.cgi?product=LibreOffice&bug_status=UNCONFIRMED&component=UI\n";
-"POT-Creation-Date: 2022-03-09 14:52:15\n"
+"POT-Creation-Date: 2022-05-04 18:07:20\n"
 "PO-Revision-Date: YYYY-MM-DD HH:MM:SS\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <EMAIL@ADDRESS>\n"
@@ -952,4 +952,24 @@ msgctxt "PYTHONSHELL"
 msgid  ""
 "The APSO extension could not be located in your LibreOffice "
 "installation."
+msgstr ""
+
+#. SFUnitTest could not locate the library gven as argument
+#. %1: The name of the library
+#, kde-format
+msgctxt "UNITTESTLIBRARY"
+msgid  ""
+"The requested library could not be located.\n"
+"The UnitTest service has not been initialized.\n"
+"\n"
+"Library name : « %1 »"
+msgstr ""
+
+#. SFUnitTest finds a RunTest() call in a inappropriate location
+#. %1: The name of a method
+#, kde-format
+msgctxt "UNITTESTMETHOD"
+msgid  ""
+"The method '%1' is unexpected in the current context.\n"
+"The UnitTest service cannot proceed further with the on-going test."
 msgstr ""
\ No newline at end of file
diff --git a/wizards/source/sfunittests/SF_Register.xba 
b/wizards/source/sfunittests/SF_Register.xba
new file mode 100644
index 000000000000..360abba50381
--- /dev/null
+++ b/wizards/source/sfunittests/SF_Register.xba
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" 
"module.dtd">
+<script:module xmlns:script="http://openoffice.org/2000/script"; 
script:name="SF_Register" script:language="StarBasic" 
script:moduleType="normal">REM 
=======================================================================================================================
+REM ===                        The ScriptForge library and its associated 
libraries are part of the LibreOffice project.                               ===
+REM    ===                                             The SFUnitTests library 
is one of the associated libraries.                                             
                        ===
+REM ===                                        Full documentation is available 
on https://help.libreoffice.org/                                                
                ===
+REM 
=======================================================================================================================
+
+Option Compatible
+Option Explicit
+
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+&apos;&apos;&apos;     SF_Register
+&apos;&apos;&apos;     ===========
+&apos;&apos;&apos;             The ScriptForge framework includes
+&apos;&apos;&apos;                     the master ScriptForge library
+&apos;&apos;&apos;                     a number of &quot;associated&quot; 
libraries SF*
+&apos;&apos;&apos;                     any user/contributor extension wanting 
to fit into the framework 
+&apos;&apos;&apos;
+&apos;&apos;&apos;             The main methods in this module allow the 
current library to cling to ScriptForge
+&apos;&apos;&apos;                     - RegisterScriptServices
+&apos;&apos;&apos;                             Register the list of services 
implemented by the current library
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+
+REM ================================================================== 
EXCEPTIONS
+
+Private Const UNITTESTLIBRARYERROR             =       
&quot;UNITTESTLIBRARYERROR&quot;
+
+REM ============================================================== PUBLIC 
METHODS
+
+REM 
-----------------------------------------------------------------------------
+Public Sub RegisterScriptServices() As Variant
+&apos;&apos;&apos;     Register into ScriptForge the list of the services 
implemented by the current library
+&apos;&apos;&apos;     Each library pertaining to the framework must implement 
its own version of this method
+&apos;&apos;&apos;
+&apos;&apos;&apos;     It consists in successive calls to the 
RegisterService() and RegisterEventManager() methods
+&apos;&apos;&apos;     with 2 arguments:
+&apos;&apos;&apos;             ServiceName: the name of the service as a 
case-insensitive string
+&apos;&apos;&apos;             ServiceReference: the reference as an object
+&apos;&apos;&apos;                     If the reference refers to a module, 
then return the module as an object:
+&apos;&apos;&apos;                             GlobalScope.Library.Module
+&apos;&apos;&apos;                     If the reference is a class instance, 
then return a string referring to the method
+&apos;&apos;&apos;                     containing the New statement creating 
the instance
+&apos;&apos;&apos;                             
&quot;libraryname.modulename.function&quot;
+
+       With GlobalScope.ScriptForge.SF_Services
+               .RegisterService(&quot;UnitTest&quot;,  
&quot;SFUnitTests.SF_Register._NewUnitTest&quot;)               &apos;  
Reference to the function initializing the service
+       End With
+
+End Sub                        &apos;  
SFUnitTests.SF_Register.RegisterScriptServices
+
+REM =========================================================== PRIVATE 
FUNCTIONS
+
+REM 
-----------------------------------------------------------------------------
+Public Function _NewUnitTest(Optional ByVal pvArgs As Variant) As Object
+&apos;&apos;&apos;     Create a new instance of the SF_UnitTest class
+&apos; Args:
+&apos;&apos;&apos;             Location: if empty, the location of the library 
is presumed to be in GlobalScope.BasicLibraries
+&apos;&apos;&apos;                     Alternatives are:
+&apos;&apos;&apos;                             - the name of a document: see 
SF_UI.WindowName
+&apos;&apos;&apos;                             - an explicit 
SFDocuments.Document instance
+&apos;&apos;&apos;                             - the component containing the 
library, typically ThisComponent
+&apos;&apos;&apos;             LibraryName: the name of the library containing 
the test code
+&apos;&apos;&apos;     Returns:
+&apos;&apos;&apos;             The instance or Nothing
+&apos;&apos;&apos;     Exceptions:
+&apos;&apos;&apos;             UNITTESTLIBRARYNOTFOUND         The library 
could not be found
+
+Dim oUnitTest As Object                                        &apos;  Return 
value
+Dim vLocation As Variant                               &apos;  Alias of 
pvArgs(0)
+Dim vLibraryName As Variant                            &apos;  alias of 
pvArgs(1)
+Dim vLocations As Variant                              &apos;  
&quot;user&quot;, &quot;share&quot; or document
+Dim sLocation As String                                        &apos;  A 
single location
+Dim sTargetLocation As String                  &apos;  &quot;user&quot; or the 
document name
+Dim vLanguages As Variant                              &apos;  
&quot;Basic&quot;, &quot;Python&quot;, ... programming languages
+Dim sLanguage As String                                        &apos;  A 
single programming language
+Dim vLibraries As Variant                              &apos;  Library names
+Dim sLibrary As String                                 &apos;  A single library
+Dim vModules As Variant                                        &apos;  Module 
names
+Dim sModule As String                                  &apos;  A single module
+Dim vModuleNames As Variant                            &apos;  Module names
+Dim oRoot As Object                                            &apos;  
com.sun.star.script.browse.BrowseNodeFactory
+Dim iLibrary As Integer                                        &apos;  The 
index of the target location in vLibraries
+
+Dim FSO As Object                                              &apos;  
SF_FileSystem
+Dim i As Integer, j As Integer, k As Integer, l As Integer
+
+Const cstService = &quot;SFUnitTests.UnitTest&quot;
+
+       If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+       If IsMissing(pvArgs) Or IsEmpty(pvArgs) Then pvArgs = Array()
+       If UBound(pvArgs) &gt;= 0 Then vLocation = pvArgs(0) Else vLocation = 
&quot;&quot;
+       If IsEmpty(vLocation) Then vLocation = &quot;&quot;
+       If UBound(pvArgs) &gt;= 1 Then vLibraryName = pvArgs(1) Else 
vLibraryName = &quot;&quot;
+       If IsEmpty(vLibraryName) Then vLibraryName = &quot;&quot;
+       If Not ScriptForge.SF_Utils._Validate(vLocation, &quot;Location&quot;, 
Array(V_STRING, ScriptForge.V_OBJECT)) Then GoTo Finally
+       If Not ScriptForge.SF_Utils._Validate(vLibraryName, 
&quot;LibraryName&quot;, V_STRING) Then GoTo Finally
+
+       Set oUnitTest = Nothing
+       Set FSO = CreateScriptService(&quot;ScriptForge.FileSystem&quot;)
+
+       &apos;  Determine the library container hosting the test code
+
+       &apos;  Browsing starts from root element
+       Set oRoot = 
SF_Utils._GetUNOService(&quot;BrowseNodeFactory&quot;).createView(com.sun.star.script.browse.BrowseNodeFactoryViewTypes.MACROORGANIZER)
+
+       If Len(vLibraryName) &gt; 0 Then
+
+               &apos;  Determine the target location, as a string. The 
location is either:
+               &apos;          - the last component of a document&apos;s file 
name
+               &apos;          - &quot;user&quot; = My Macros &amp; Dialogs
+               If VarType(vLocation) = ScriptForge.V_OBJECT Then
+                       sTargetLocation = FSO.GetName(vLocation.URL)
+               ElseIf Len(vLocation) = 0 Then
+                       sTargetLocation = &quot;user&quot;              &apos;  
Testing code is presumed NOT in &quot;share&quot;
+               Else
+                       sTargetLocation = FSO.GetName(vLocation)
+               End If
+
+               &apos;  Exploration is done via tree nodes
+               iLibrary = -1
+               If Not IsNull(oRoot) Then
+                       If oRoot.hasChildNodes() Then
+                               vLocations = oRoot.getChildNodes()
+                               For i = 0 To UBound(vLocations)
+                                       sLocation = vLocations(i).getName()
+                                       If sLocation = sTargetLocation Then
+                                               If 
vLocations(i).hasChildNodes() Then
+                                                       vLanguages = 
vLocations(i).getChildNodes()
+                                                       For j = 0 To 
UBound(vLanguages)
+                                                               sLanguage = 
vLanguages(j).getName()
+                                                               &apos;  
Consider Basic libraries only
+                                                               If sLanguage = 
&quot;Basic&quot; Then
+                                                                       If 
vLanguages(j).hasChildNodes() Then
+                                                                               
vLibraries = vLanguages(j).getChildNodes()
+                                                                               
For k = 0 To UBound(vLibraries)
+                                                                               
        sLibrary = vLibraries(k).getName()
+                                                                               
        &apos;  Consider the targeted library only
+                                                                               
        If sLibrary = vLibraryName Then
+                                                                               
                iLibrary = k
+                                                                               
                If vLibraries(k).hasChildNodes() Then
+                                                                               
                        vModules = vLibraries(k).getChildNodes()
+                                                                               
                        vModuleNames = Array()
+                                                                               
                        For l = 0 To UBound(vModules)
+                                                                               
                                sModule = vModules(l).getName()
+                                                                               
                                vModuleNames = 
ScriptForge.SF_Array.Append(vModuleNames, sModule)
+                                                                               
                        Next l
+                                                                               
                End If
+                                                                               
                Exit For
+                                                                               
        End If
+                                                                               
Next k
+                                                                       End If
+                                                               End If
+                                                               If iLibrary 
&gt;= 0 Then Exit For
+                                                       Next j
+                                               End If
+                                       End If
+                                       If iLibrary &gt;= 0 Then Exit For
+                               Next i
+                       End If
+               End If
+               If iLibrary &lt; 0 Then GoTo CatchLibrary
+
+       End If
+
+Try:
+       &apos;  Create the unittest Basic object and initialize its attributes
+       Set oUnitTest = New SF_UnitTest
+       With oUnitTest
+               Set .[Me] = oUnitTest
+               If Len(vLibraryName) &gt; 0 Then
+                       .LibrariesContainer = sTargetLocation
+                       .Scope = Iif(sTargetLocation = &quot;user&quot;, 
&quot;application&quot;, &quot;document&quot;)
+                       .Libraries = vLibraries
+                       .LibraryName = sLibrary
+                       .LibraryIndex = iLibrary
+                       .Modules = vModules
+                       .ModuleNames = vModuleNames
+                       ._ExecutionMode = .FULLMODE
+                       ._WhenAssertionFails = .FAILSTOPSUITE
+                       &apos;  Launch the test timer
+                       .TestTimer = 
CreateScriptService(&quot;ScriptForge.Timer&quot;, True)
+               Else
+                       ._ExecutionMode = .SIMPLEMODE
+                       ._WhenAssertionFails = .FAILIMMEDIATESTOP
+               End If
+       End With
+
+Finally:
+       Set _NewUnitTest = oUnitTest
+       Exit Function
+Catch:
+       GoTo Finally
+CatchLibrary:
+       ScriptForge.SF_Exception.RaiseFatal(UNITTESTLIBRARYERROR, vLibraryName)
+       GoTo Finally
+End Function   &apos;  SFUnitTests.SF_Register._NewUnitTest
+
+REM ============================================== END OF 
SFUNITTESTS.SF_REGISTER
+</script:module>
\ No newline at end of file
diff --git a/wizards/source/sfunittests/SF_UnitTest.xba 
b/wizards/source/sfunittests/SF_UnitTest.xba
new file mode 100644
index 000000000000..c3a1daa9dc9d
--- /dev/null
+++ b/wizards/source/sfunittests/SF_UnitTest.xba
@@ -0,0 +1,1820 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" 
"module.dtd">
+<script:module xmlns:script="http://openoffice.org/2000/script"; 
script:name="SF_UnitTest" script:language="StarBasic" 
script:moduleType="normal">REM 
=======================================================================================================================
+REM ===                        The ScriptForge library and its associated 
libraries are part of the LibreOffice project.                               ===
+REM ===                                        Full documentation is available 
on https://help.libreoffice.org/                                                
                ===
+REM 
=======================================================================================================================
+
+Option Compatible
+Option ClassModule
+
+Option Explicit
+
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+&apos;&apos;&apos;     SF_UnitTest
+&apos;&apos;&apos;     ===========
+&apos;&apos;&apos;             Class providing a framework to execute and 
check sets of unit tests.
+&apos;&apos;&apos;
+&apos;&apos;&apos;             The UnitTest unit testing framework was 
originally inspired by unittest.py in Python
+&apos;&apos;&apos;             and has a similar flavor as major unit testing 
frameworks in other languages.
+&apos;&apos;&apos;
+&apos;&apos;&apos;             It supports test automation, sharing of setup 
and shutdown code for tests,
+&apos;&apos;&apos;             aggregation of tests into collections.
+&apos;&apos;&apos;
+&apos;&apos;&apos;             Both the
+&apos;&apos;&apos;                     - code describing the unit tests
+&apos;&apos;&apos;                     - code to be tested
+&apos;&apos;&apos;             must be written exclusively in Basic (the code 
might call functions written in other languages).
+&apos;&apos;&apos;             Even if either code may be contained in the 
same module, a much better practice is to
+&apos;&apos;&apos;             store them in separate libraries.
+&apos;&apos;&apos;             Typically:
+&apos;&apos;&apos;                     - in a same document when the code to 
be tested is contained in that document
+&apos;&apos;&apos;                     - either in a &quot;test&quot; document 
or in a &quot;My Macros&quot; library when the code
+&apos;&apos;&apos;                       to be tested is a shared library (My 
Macros or LibreOffice Macros).
+&apos;&apos;&apos;             The code to be tested may be released as an 
extension. It does not need to make
+&apos;&apos;&apos;             use of ScriptForge services in any way.
+&apos;&apos;&apos;
+&apos;&apos;&apos;             The test reporting device is the Console. Read 
abount the console in the ScriptForge.Exception service.
+&apos;&apos;&apos;
+&apos;&apos;&apos;             Definitions:
+&apos;&apos;&apos;                     - Test Case
+&apos;&apos;&apos;                             A test case is the individual 
unit of testing.
+&apos;&apos;&apos;                             It checks for a specific 
response to a particular set of inputs.
+&apos;&apos;&apos;                             A test case in the UnitTest 
service is represented by a Basic Sub.
+&apos;&apos;&apos;                             The name of the Sub starts 
conventionally with &quot;Test_&quot;.
+&apos;&apos;&apos;                             The test fails if one of the 
included AssertXXX methods returns False
+&apos;&apos;&apos;                     - Test Suite
+&apos;&apos;&apos;                             A test suite is a collection of 
test cases that should be executed together.
+&apos;&apos;&apos;                             A test suite is represented by 
a Basic module.
+&apos;&apos;&apos;                             A suite may include the tasks 
needed to prepare one or more tests, and any associated cleanup actions.
+&apos;&apos;&apos;                             This may involve, for example, 
creating temporary files or directories, opening a document, loading libraries.
+&apos;&apos;&apos;                             Conventionally those tasks are 
part pf the SetUp&apos;) and TearDown() methods.
+&apos;&apos;&apos;                     - Unit test
+&apos;&apos;&apos;                             A full unit test is a set of 
test suites (each suite in a separate Basic module),
+&apos;&apos;&apos;                             each of them being a set of 
test cases (each case is located in a separate Basic Sub).
+&apos;&apos;&apos;
+&apos;&apos;&apos;             Two modes:
+&apos;&apos;&apos;                     Beside the normal mode (&quot;full 
mode&quot;), using test suites and test cases, a second mode exists, called 
&quot;simple mode&quot;
+&apos;&apos;&apos;                     limited to the use exclusively of the 
Assert...() methods.
+&apos;&apos;&apos;                     Their boolean returned value may 
support the execution of limited unit tests.                           
+&apos;&apos;&apos;
+&apos;&apos;&apos;             Service invocation examples:
+&apos;&apos;&apos;                     In full mode, the service creation is 
external to test cases
+&apos;&apos;&apos;                             Dim myUnitTest As Variant
+&apos;&apos;&apos;                             myUnitTest = 
CreateScriptService(&quot;UnitTest&quot;, ThisComponent, &quot;Tests&quot;)
+&apos;&apos;&apos;                                                             
&apos;  Test code is in the library &quot;Tests&quot; located in the current 
document
+&apos;&apos;&apos;                     In simple mode, the service creation is 
internal to every test case
+&apos;&apos;&apos;                             Dim myUnitTest As Variant
+&apos;&apos;&apos;                             myUnitTest = 
CreateScriptService(&quot;UnitTest&quot;)
+&apos;&apos;&apos;                             With myUnitTest
+&apos;&apos;&apos;                                     If Not .AssertTrue(...) 
Then ...                        &apos;  Only calls to the Assert...() methods 
are allowed
+&apos;&apos;&apos;                                     &apos;  ...
+&apos;&apos;&apos;                                     .Dispose()
+&apos;&apos;&apos;                             End With
+&apos;&apos;&apos;
+&apos;&apos;&apos;             Minimalist full mode example
+&apos;&apos;&apos;                     Code to be tested (stored in library 
&quot;Standard&quot; of document &quot;MyDoc.ods&quot;) :
+&apos;&apos;&apos;                             Function ArraySize(arr As 
Variant) As Long
+&apos;&apos;&apos;                                     If IsArray(arr) Then 
ArraySize = UBound(arr) - LBound(arr) + 1 Else ArraySize = -1
+&apos;&apos;&apos;                             End Function
+&apos;&apos;&apos;                     Test code (stored in module 
&quot;AllTests&quot; of library &quot;Tests&quot; of document 
&quot;MyDoc.ods&quot;) :
+&apos;&apos;&apos;                             Sub Main()              &apos;  
Sub to trigger manually, f.i. from the Tools + Run Macro tabbed bar
+&apos;&apos;&apos;                                     
GlobalScope.BasicLibraries.loadLibrary(&quot;ScriptForge&quot;)
+&apos;&apos;&apos;                                     Dim test        :       
test = CreateScriptService(&quot;UnitTest&quot;, ThisComponent, 
&quot;Tests&quot;)
+&apos;&apos;&apos;                                     
test.RunTest(&quot;AllTests&quot;)      &apos;  AllTests is a module name ; 
test cases are named &quot;Test_*&quot; (default)
+&apos;&apos;&apos;                                     test.Dispose()
+&apos;&apos;&apos;                             End Sub
+&apos;&apos;&apos;                             REM 
------------------------------------------------------------------------------
+&apos;&apos;&apos;                             Sub Setup(test)                 
                &apos;  The unittest service is passed as argument
+&apos;&apos;&apos;                                     &apos;  Optional Sub to 
initialize processing of the actual test suite
+&apos;&apos;&apos;                                     Dim exc         :       
exc = CreateScriptService(&quot;Exception&quot;)
+&apos;&apos;&apos;                                     exc.Console(Modal := 
False)     &apos;  Watch test progress in the console
+&apos;&apos;&apos;                             End Sub
+&apos;&apos;&apos;                             REM 
------------------------------------------------------------------------------
+&apos;&apos;&apos;                             Sub Test_ArraySize(test)
+&apos;&apos;&apos;                                     On Local Error GoTo 
CatchErr
+&apos;&apos;&apos;                                     
test.AssertEqual(ArraySize(10), -1, &quot;When not array&quot;)
+&apos;&apos;&apos;                                     
test.AssertEqual(ArraySize(Array(1, 2, 3)), 3, &quot;When simple array&quot;)
+&apos;&apos;&apos;                                     
test.AssertEqual(ArraySize(DimArray(3)), 4, &quot;When array with empty 
items&quot;)
+&apos;&apos;&apos;                                     Exit Sub
+&apos;&apos;&apos;                             CatchErr:
+&apos;&apos;&apos;                                     
test.ReportError(&quot;ArraySize() is corrupt&quot;)
+&apos;&apos;&apos;                             End Sub
+&apos;&apos;&apos;                             REM 
------------------------------------------------------------------------------
+&apos;&apos;&apos;                             Sub TearDown(test)
+&apos;&apos;&apos;                                     &apos;  Optional Sub to 
finalize processing of the actual test suite
+&apos;&apos;&apos;                             End Sub
+&apos;&apos;&apos;
+&apos;&apos;&apos;             Error handling
+&apos;&apos;&apos;                     To support the debugging of the tested 
code, the UnitTest service, in cases of
+&apos;&apos;&apos;                             - assertion failure
+&apos;&apos;&apos;                             - Basic run-time error in the 
tested code
+&apos;&apos;&apos;                             - Basic run-time error in the 
testing code (the unit tests)
+&apos;&apos;&apos;                     will comment the error location and 
description in a message box and in the console log,
+&apos;&apos;&apos;                     providing every test case (in either 
mode) implements an error handler containing at least:
+&apos;&apos;&apos;                             Sub Test_Case1(test As Variant)
+&apos;&apos;&apos;                                     On Local Error GoTo 
Catch
+&apos;&apos;&apos;                                     &apos; ... 
(AssertXXX(), Fail(), ...)
+&apos;&apos;&apos;                                     Exit Sub
+&apos;&apos;&apos;                             Catch:
+&apos;&apos;&apos;                                     test.ReportError()
+&apos;&apos;&apos;                             End Sub
+&apos;&apos;&apos;
+&apos;&apos;&apos;             Detailed user documentation:
+&apos;&apos;&apos;                     
https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_unittest.html?DbPAR=BASIC
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+
+REM ================================================================== 
EXCEPTIONS
+
+Private Const UNITTESTMETHODERROR              =       
&quot;UNITTESTMETHODERROR&quot;
+
+REM ============================================================= PRIVATE 
MEMBERS
+
+Private [Me]                           As Object
+Private [_Parent]                      As Object
+Private ObjectType                     As String               &apos; Must be 
&quot;UNITTEST&quot;
+Private ServiceName                    As String
+
+&apos; Testing code
+Private LibrariesContainer     As String               &apos; Document or user 
Basic library containing the test library
+Private Scope                          As String               &apos; Scope 
when running a Basic script with Session.ExecuteBasicScript()
+Private Libraries                      As Variant              &apos; Set of 
libraries
+Private LibraryName                    As String               &apos; Name of 
the library containing the test code
+Private LibraryIndex           As Integer              &apos; Index in 
Libraries
+Private Modules                                As Variant              &apos; 
Set of modules
+Private ModuleNames                    As Variant              &apos; Set of 
module names
+Private MethodNames                    As Variant              &apos; Set of 
methods in a given module
+
+&apos; Internals
+Private _Verbose                       As Boolean              &apos; When 
True, every assertion is reported,failing or not
+Private _LongMessage           As Boolean              &apos; When False, only 
the message provided by the tester is considered
+                                                                               
        &apos; When True (default), that message is appended to the standard 
message
+Private _WhenAssertionFails    As Integer              &apos; Determines what 
to do when a test fails
+
+&apos; Test status
+Private _Status                                As Integer              &apos; 
0 = standby
+                                                                               
        &apos; 1 = test suite started
+                                                                               
        &apos; 2 = setup started
+                                                                               
        &apos; 3 = test case started
+                                                                               
        &apos; 4 = teardown started
+Private _ExecutionMode         As Integer              &apos; 1 = Test started 
with RunTest()
+                                                                               
        &apos; 2 = Test started with CreateScriptService()      Only Assert() 
methods allowed
+Private _Module                                As String               &apos; 
Exact name of module currently running
+Private _TestCase                      As String               &apos; Exact 
name of test case currently running
+Private _ReturnCode                    As Integer              &apos; 0 = 
Normal end
+                                                                               
        &apos; 1 = Assertion failed
+                                                                               
        &apos; 2 = Skip request (in Setup() only)
+                                                                               
        &apos;-1 = abnormal end
+Private _FailedAssert          As String               &apos; Assert function 
that returned a failure
+
+&apos; Timers
+Private TestTimer                      As Object               &apos; Started 
by CreateScriptService()
+Private SuiteTimer                     As Object               &apos; Started 
by RunTest()
+Private CaseTimer                      As Object               &apos; Started 
by new case
+
+&apos; Services
+Private Exception                      As Object               &apos; 
SF_Exception
+Private Session                                As Object               &apos; 
SF_Session
+
+REM ============================================================ MODULE 
CONSTANTS
+
+&apos; When assertion fails constants: error is reported + ...
+Global Const FAILIGNORE                        = 0                     &apos; 
Ignore the failure
+Global Const FAILSTOPSUITE             = 1                     &apos; Module 
TearDown is executed, then next suite may be started (default in full mode)
+Global Const FAILIMMEDIATESTOP = 2                     &apos; Stop immediately 
(default in simple mode)
+
+&apos; Unit tests status (internal use only =&gt; not Global)
+Const STATUSSTANDBY                            = 0                     &apos; 
No test active
+Const STATUSSUITESTARTED               = 1                     &apos; 
RunTest() started
+Const STATUSSETUP                              = 2                     &apos; 
A Setup() method is running
+Const STATUSTESTCASE                   = 3                     &apos; A test 
case is running
+Const STATUSTEARDOWN                   = 4                     &apos; A 
TearDown() method is running
+
+&apos; Return codes
+Global Const RCNORMALEND               = 0                     &apos; Normal 
end of test or test not started
+Global Const RCASSERTIONFAILED = 1                     &apos; An assertion 
within a test case returned False
+Global Const RCSKIPTEST                        = 2                     &apos; 
A SkipTest() was issued by a Setup() method
+Global Const RCABORTTEST               = 3                     &apos; Abnormal 
end of test
+
+&apos; Execution modes
+Global Const FULLMODE                  = 1                     &apos; 1 = Test 
started with RunTest()
+Global Const SIMPLEMODE                        = 2                     &apos; 
2 = Test started with CreateScriptService()      Only Assert() methods allowed
+
+Const INVALIDPROCEDURECALL             = &quot;5&quot;         &apos; 
Artificial error raised when an assertion fails
+
+REM ===================================================== 
CONSTRUCTOR/DESTRUCTOR
+
+REM 
-----------------------------------------------------------------------------
+Private Sub Class_Initialize()
+       Set [Me] = Nothing
+       Set [_Parent] = Nothing
+       ObjectType = &quot;UNITTEST&quot;
+       ServiceName = &quot;SFUnitTests.UnitTest&quot;
+       LibrariesContainer = &quot;&quot;
+       Scope = &quot;&quot;
+       Libraries = Array()
+       LibraryName = &quot;&quot;
+       LibraryIndex = -1
+       _Verbose = False
+       _LongMessage = True
+       _WhenAssertionFails = -1
+       _Status = STATUSSTANDBY
+       _ExecutionMode = SIMPLEMODE
+       _Module = &quot;&quot;
+       _TestCase = &quot;&quot;
+       _ReturnCode = RCNORMALEND
+       _FailedAssert = &quot;&quot;
+       Set TestTimer = Nothing
+       Set SuiteTimer = Nothing
+       Set CaseTimer = Nothing
+       Set Exception = CreateScriptService(&quot;ScriptForge.Exception&quot;)
+       Set Session = CreateScriptService(&quot;ScriptForge.Session&quot;)
+End Sub                &apos;  SFUnitTests.SF_UnitTest Constructor
+
+REM 
-----------------------------------------------------------------------------
+Private Sub Class_Terminate()
+       If Not IsNull(CaseTimer) Then CaseTimer = CaseTimer.Dispose()
+       If Not IsNull(SuiteTimer) Then SuiteTimer = SuiteTimer.Dispose()
+       If Not IsNull(TestTimer) Then TestTimer = TestTimer.Dispose()
+       Call Class_Initialize()
+End Sub                &apos;  SFUnitTests.SF_UnitTest Destructor
+
+REM 
-----------------------------------------------------------------------------
+Public Function Dispose() As Variant
+       Call Class_Terminate()
+       Set Dispose = Nothing
+End Function   &apos;  SFUnitTests.SF_UnitTest Explicit destructor
+
+REM ================================================================== 
PROPERTIES
+
+REM 
-----------------------------------------------------------------------------
+Property Get LongMessage() As Variant
+&apos;&apos;&apos;     When False, only the message provided by the tester is 
considered
+&apos;&apos;&apos;     When True (default), that message is appended to the 
standard message
+       LongMessage = _PropertyGet(&quot;LongMessage&quot;)
+End Property   &apos;  SFUnitTests.SF_UnitTest.LongMessage (get)
+
+REM 
-----------------------------------------------------------------------------
+Property Let LongMessage(Optional ByVal pvLongMessage As Variant)
+&apos;&apos;&apos;     Set the updatable property LongMessage
+       _PropertySet(&quot;LongMessage&quot;, pvLongMessage)
+End Property   &apos;  SFUnitTests.SF_UnitTest.LongMessage (let)
+
+REM 
-----------------------------------------------------------------------------
+Property Get ReturnCode() As Integer
+&apos;&apos;&apos;     RCNORMALEND                     = 0                     
        &apos; Normal end of test or test not started
+&apos;&apos;&apos;     RCASSERTIONFAILED       = 1                             
&apos; An assertion within a test case returned False
+&apos;&apos;&apos;     RCSKIPTEST                      = 2                     
        &apos; A SkipTest() was issued by a Setup() method
+&apos;&apos;&apos;     RCABORTTEST                     = 3                     
        &apos; Abnormal end of test
+       ReturnCode = _PropertyGet(&quot;ReturnCode&quot;)
+End Property   &apos;  SFUnitTests.SF_UnitTest.ReturnCode (get)
+
+REM 
-----------------------------------------------------------------------------
+Property Get Verbose() As Variant
+&apos;&apos;&apos;     The Verbose property indicates if all sertions are 
reported
+       Verbose = _PropertyGet(&quot;Verbose&quot;)
+End Property   &apos;  SFUnitTests.SF_UnitTest.Verbose (get)
+
+REM 
-----------------------------------------------------------------------------
+Property Let Verbose(Optional ByVal pvVerbose As Variant)
+&apos;&apos;&apos;     Set the updatable property Verbose
+       _PropertySet(&quot;Verbose&quot;, pvVerbose)
+End Property   &apos;  SFUnitTests.SF_UnitTest.Verbose (let)
+
+REM 
-----------------------------------------------------------------------------
+Property Get WhenAssertionFails() As Variant
+&apos;&apos;&apos;     What when an AssertXXX() method returns False
+&apos;&apos;&apos;             FAILIGNORE                      = 0             
                &apos; Ignore the failure
+&apos;&apos;&apos;             FAILSTOPSUITE           = 1                     
        &apos; Module TearDown is executed, then next suite may be started 
(default in FULL mode)
+&apos;&apos;&apos;             FAILIMMEDIATESTOP       = 2                     
        &apos; Stop immediately (default in SIMPLE mode)
+&apos;&apos;&apos;     In simple mode, only FAILIGNORE and FAILIMMEDIATESTOP 
are allowed.
+&apos;&apos;&apos;     In both modes, when WhenAssertionFails has not the 
value FAILIGNORE,
+&apos;&apos;&apos;     each test case MUST have a run-time error handler 
calling the ReportError() method.
+&apos;&apos;&apos;     Example:
+&apos;&apos;&apos;             Sub Test_sometest(Optional test)
+&apos;&apos;&apos;                     On Local Error GoTo CatchError
+&apos;&apos;&apos;                     &apos;  ...     one or more assert verbs
+&apos;&apos;&apos;                     Exit Sub
+&apos;&apos;&apos;             CatchError:
+&apos;&apos;&apos;                     test.ReportError()
+&apos;&apos;&apos;             End Sub
+       WhenAssertionFails = _PropertyGet(&quot;WhenAssertionFails&quot;)
+End Property   &apos;  SFUnitTests.SF_UnitTest.WhenAssertionFails (get)
+
+REM 
-----------------------------------------------------------------------------
+Property Let WhenAssertionFails(Optional ByVal pvWhenAssertionFails As Variant)
+&apos;&apos;&apos;     Set the updatable property WhenAssertionFails
+       _PropertySet(&quot;WhenAssertionFails&quot;, pvWhenAssertionFails)
+End Property   &apos;  SFUnitTests.SF_UnitTest.WhenAssertionFails (let)
+
+REM ===================================================================== 
METHODS
+
+REM 
-----------------------------------------------------------------------------
+Public Function AssertAlmostEqual(Optional ByRef A As Variant _
+                                                               , Optional 
ByRef B As Variant _
+                                                               , Optional 
ByVal Tolerance As Variant _
+                                                               , Optional 
ByVal Message As Variant _
+                                                               ) As Boolean
+&apos;&apos;&apos;     Returns True when A and B are numerical values and are 
found close to each other.
+&apos;&apos;&apos;     It is typically used to compare very large or very 
small numbers.
+&apos;&apos;&apos;     Equality is confirmed when
+&apos;&apos;&apos;             - A and B can be converted to doubles
+&apos;&apos;&apos;             - The absolute difference between a and b, 
relative to the larger absolute value of a or b,
+&apos;&apos;&apos;               is lower or equal to the tolerance. The 
default tolerance is 1E-09,
+&apos;&apos;&apos;                     Examples:       1E+12 and 1E+12 + 100 
are almost equal
+&apos;&apos;&apos;                                             1E-20 and 2E-20 
are not almost equal
+&apos;&apos;&apos;                                             100 and 95 are 
almost equal when Tolerance = 0.05
+
+Dim bAssert As Boolean                 &apos;  Return value
+Const cstTolerance = 1E-09
+Const cstThisSub = &quot;UnitTest.AssertAlmostEqual&quot;
+Const cstSubArgs = &quot;A, B, [Tolerance=1E-09], 
[Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+       If IsMissing(A) Then A = Empty
+       If IsMissing(B) Then B = Empty
+       If IsMissing(Tolerance) Then Tolerance = cstTolerance
+       If IsMissing(Message) Then Message = &quot;&quot;
+       ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)     &apos;  
Unconditional !
+       If Not ScriptForge.SF_Utils._Validate(Tolerance, &quot;Tolerance&quot;, 
ScriptForge.V_NUMERIC) Then GoTo Catch
+
+Try:
+       bAssert = _Assert(&quot;AssertAlmostEqual&quot;, True, A, B, Message, 
Tolerance)
+
+Finally:
+       AssertAlmostEqual = bAssert
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+Catch:
+       bAssert = False
+       GoTo Finally
+End Function   &apos;  SFUnitTests.SF_UnitTest.AssertAlmostEqual
+
+REM 
-----------------------------------------------------------------------------
+Public Function AssertEqual(Optional ByRef A As Variant _
+                                                               , Optional 
ByRef B As Variant _
+                                                               , Optional 
ByVal Message As Variant _
+                                                               ) As Boolean
+&apos;&apos;&apos;     Returns True when A and B are found equal.
+&apos;&apos;&apos;     Equality is confirmed when
+&apos;&apos;&apos;             If A and B are scalars:
+&apos;&apos;&apos;                     They should have the same VarType or 
both be numeric
+&apos;&apos;&apos;                     Booleans and numeric values are 
compared with the = operator
+&apos;&apos;&apos;                     Strings are compared with the StrComp() 
builtin function. The comparison is case-sensitive
+&apos;&apos;&apos;                     Dates and times are compared up to the 
second
+&apos;&apos;&apos;                     Null, Empty and Nothing are not equal, 
but AssertEqual(Nothing, Nothing) returns True
+&apos;&apos;&apos;                     UNO objects are compared with the 
EqualUnoObjects() method
+&apos;&apos;&apos;                     Basic objects are NEVER equal
+&apos;&apos;&apos;             If A and B are arrays:
+&apos;&apos;&apos;                     They should have the same number of 
dimensions (maximum 2)
+&apos;&apos;&apos;                     The lower and upper bounds must be 
identical for each dimension
+&apos;&apos;&apos;                     Two empty arrays are equal
+&apos;&apos;&apos;                     Their items must be equal one by one
+
+Dim bAssert As Boolean                 &apos;  Return value
+Const cstThisSub = &quot;UnitTest.AssertEqual&quot;
+Const cstSubArgs = &quot;A, B, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+       If IsMissing(A) Then A = Empty
+       If IsMissing(B) Then B = Empty
+       If IsMissing(Message) Then Message = &quot;&quot;
+       ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)     &apos;  
Unconditional !
+
+Try:
+       bAssert = _Assert(&quot;AssertEqual&quot;, True, A, B, Message)
+
+Finally:
+       AssertEqual = bAssert
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+End Function   &apos;  SFUnitTests.SF_UnitTest.AssertEqual
+
+REM 
-----------------------------------------------------------------------------
+Public Function AssertFalse(Optional ByRef A As Variant _
+                                                               , Optional 
ByVal Message As Variant _
+                                                               ) As Boolean
+&apos;&apos;&apos;     Returns True when A is a Boolean and its value is False
+
+Dim bAssert As Boolean                 &apos;  Return value
+Const cstThisSub = &quot;UnitTest.AssertFalse&quot;
+Const cstSubArgs = &quot;A, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+       If IsMissing(A) Then A = Empty
+       If IsMissing(Message) Then Message = &quot;&quot;
+       ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)     &apos;  
Unconditional !
+
+Try:
+       bAssert = _Assert(&quot;AssertFalse&quot;, True, A, Empty, Message)
+
+Finally:
+       AssertFalse = bAssert
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+End Function   &apos;  SFUnitTests.SF_UnitTest.AssertFalse
+
+REM 
-----------------------------------------------------------------------------
+Public Function AssertGreater(Optional ByRef A As Variant _
+                                                               , Optional 
ByRef B As Variant _
+                                                               , Optional 
ByVal Message As Variant _
+                                                               ) As Boolean
+&apos;&apos;&apos;     Returns True when A is greater than B.
+&apos;&apos;&apos;     To compare A and B:
+&apos;&apos;&apos;             They should have the same VarType or both be 
numeric
+&apos;&apos;&apos;             Elgible datatypes are String, Date or numeric.
+&apos;&apos;&apos;             String comparisons are case-sensitive.
+
+Dim bAssert As Boolean                 &apos;  Return value
+Const cstThisSub = &quot;UnitTest.AssertGreater&quot;
+Const cstSubArgs = &quot;A, B, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+       If IsMissing(A) Then A = Empty
+       If IsMissing(B) Then B = Empty
+       If IsMissing(Message) Then Message = &quot;&quot;
+       ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)     &apos;  
Unconditional !
+
+Try:
+       bAssert = _Assert(&quot;AssertGreater&quot;, True, A, B, Message)
+
+Finally:
+       AssertGreater = bAssert
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+End Function   &apos;  SFUnitTests.SF_UnitTest.AssertGreater
+
+REM 
-----------------------------------------------------------------------------
+Public Function AssertGreaterEqual(Optional ByRef A As Variant _
+                                                               , Optional 
ByRef B As Variant _
+                                                               , Optional 
ByVal Message As Variant _
+                                                               ) As Boolean
+&apos;&apos;&apos;     Returns True when A is greater than or equal to B.
+&apos;&apos;&apos;     To compare A and B:
+&apos;&apos;&apos;             They should have the same VarType or both be 
numeric
+&apos;&apos;&apos;             Elgible datatypes are String, Date or numeric.
+&apos;&apos;&apos;             String comparisons are case-sensitive.
+
+Dim bAssert As Boolean                 &apos;  Return value
+Const cstThisSub = &quot;UnitTest.AssertGreaterEqual&quot;
+Const cstSubArgs = &quot;A, B, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+       If IsMissing(A) Then A = Empty
+       If IsMissing(B) Then B = Empty
+       If IsMissing(Message) Then Message = &quot;&quot;
+       ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)     &apos;  
Unconditional !
+
+Try:
+       bAssert = _Assert(&quot;AssertGreaterEqual&quot;, True, A, B, Message)
+
+Finally:
+       AssertGreaterEqual = bAssert
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+End Function   &apos;  SFUnitTests.SF_UnitTest.AssertGreaterEqual
+
+REM 
-----------------------------------------------------------------------------
+Public Function AssertIn(Optional ByRef A As Variant _
+                                                               , Optional 
ByRef B As Variant _
+                                                               , Optional 
ByVal Message As Variant _
+                                                               ) As Boolean
+&apos;&apos;&apos;     Returns True when A, a string, is found within B
+&apos;&apos;&apos;     B may be a 1D array, a ScriptForge dictionary or a 
string.
+&apos;&apos;&apos;     When B is an array, A may be a date or a numeric value.
+&apos;&apos;&apos;     String comparisons are case-sensitive.
+
+Dim bAssert As Boolean                 &apos;  Return value
+Const cstThisSub = &quot;UnitTest.AssertIn&quot;
+Const cstSubArgs = &quot;A, B, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+       If IsMissing(A) Then A = Empty
+       If IsMissing(B) Then B = Empty
+       If IsMissing(Message) Then Message = &quot;&quot;
+       ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)     &apos;  
Unconditional !
+
+Try:
+       bAssert = _Assert(&quot;AssertIn&quot;, True, A, B, Message)
+
+Finally:
+       AssertIn = bAssert
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+End Function   &apos;  SFUnitTests.SF_UnitTest.AssertIn
+
+REM 
-----------------------------------------------------------------------------
+Public Function AssertIsInstance(Optional ByRef A As Variant _
+                                                               , Optional 
ByRef ObjectType As Variant _
+                                                               , Optional 
ByVal Message As Variant _
+                                                               ) As Boolean
+&apos;&apos;&apos;     Returns True when A is an object instance of the class 
ObjectType or a variable of type ObjectType.
+&apos;&apos;&apos;     A may be:
+&apos;&apos;&apos;             - a ScriptForge object
+&apos;&apos;&apos;                     ObjectType is a string like 
&quot;DICTIONARY&quot;, &quot;calc&quot;, &quot;Dialog&quot;, 
&quot;exception&quot;, etc.
+&apos;&apos;&apos;             - a UNO object
+&apos;&apos;&apos;                     ObjectType is a string identical with 
values returned by the SF_Session.UnoObjectType()
+&apos;&apos;&apos;             - any variable, providing it is neither an 
object nor an array
+&apos;&apos;&apos;                     ObjectType is a string identifying a 
value returned by the TypeName() builtin function
+&apos;&apos;&apos;             - an array
+&apos;&apos;&apos;                     ObjectType is expected to be 
&quot;array&quot;
+
+Dim bAssert As Boolean                 &apos;  Return value
+Const cstThisSub = &quot;UnitTest.AssertIsInstance&quot;
+Const cstSubArgs = &quot;A, ObjectType, 
[Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+       If IsMissing(A) Then A = Empty
+       If IsMissing(ObjectType) Then ObjectType = Empty
+       If IsMissing(Message) Then Message = &quot;&quot;
+       ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)     &apos;  
Unconditional !
+       If Not ScriptForge.SF_Utils._Validate(ObjectType, 
&quot;ObjectType&quot;, V_STRING) Then GoTo Catch
+
+
+Try:
+       bAssert = _Assert(&quot;AssertIsInstance&quot;, True, A, Empty, 
Message, ObjectType)
+
+Finally:
+       AssertIsInstance = bAssert
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+Catch:
+       bAssert = False
+       GoTo Finally
+End Function   &apos;  SFUnitTests.SF_UnitTest.AssertIsInstance
+
+REM 
-----------------------------------------------------------------------------
+Public Function AssertIsNothing(Optional ByRef A As Variant _
+                                                               , Optional 
ByVal Message As Variant _
+                                                               ) As Boolean
+&apos;&apos;&apos;     Returns True when A is an object that has the Nothing 
value
+
+Dim bAssert As Boolean                 &apos;  Return value
+Const cstThisSub = &quot;UnitTest.AssertIsNothing&quot;
+Const cstSubArgs = &quot;A, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+       If IsMissing(A) Then A = Empty
+       If IsMissing(Message) Then Message = &quot;&quot;
+       ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)     &apos;  
Unconditional !
+
+Try:
+       bAssert = _Assert(&quot;AssertIsNothing&quot;, True, A, Empty, Message)
+
+Finally:
+       AssertIsNothing = bAssert
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+End Function   &apos;  SFUnitTests.SF_UnitTest.AssertIsNothing
+
+REM 
-----------------------------------------------------------------------------
+Public Function AssertIsNull(Optional ByRef A As Variant _
+                                                               , Optional 
ByVal Message As Variant _
+                                                               ) As Boolean
+&apos;&apos;&apos;     Returns True when A has the Null value
+
+Dim bAssert As Boolean                 &apos;  Return value
+Const cstThisSub = &quot;UnitTest.AssertIsNull&quot;
+Const cstSubArgs = &quot;A, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+       If IsMissing(A) Then A = Empty
+       If IsMissing(Message) Then Message = &quot;&quot;
+       ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)     &apos;  
Unconditional !
+
+Try:
+       bAssert = _Assert(&quot;AssertIsNull&quot;, True, A, Empty, Message)
+
+Finally:
+       AssertIsNull = bAssert
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+End Function   &apos;  SFUnitTests.SF_UnitTest.AssertIsNull
+
+REM 
-----------------------------------------------------------------------------
+Public Function AssertLess(Optional ByRef A As Variant _
+                                                               , Optional 
ByRef B As Variant _
+                                                               , Optional 
ByVal Message As Variant _
+                                                               ) As Boolean
+&apos;&apos;&apos;     Returns True when A is less than B.
+&apos;&apos;&apos;     To compare A and B:
+&apos;&apos;&apos;             They should have the same VarType or both be 
numeric
+&apos;&apos;&apos;             Elgible datatypes are String, Date or numeric.
+&apos;&apos;&apos;             String comparisons are case-sensitive.
+
+Dim bAssert As Boolean                 &apos;  Return value
+Const cstThisSub = &quot;UnitTest.AssertLess&quot;
+Const cstSubArgs = &quot;A, B, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+       If IsMissing(A) Then A = Empty
+       If IsMissing(B) Then B = Empty
+       If IsMissing(Message) Then Message = &quot;&quot;
+       ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)     &apos;  
Unconditional !
+
+Try:
+       bAssert = _Assert(&quot;AssertLess&quot;, False, A, B, Message)
+
+Finally:
+       AssertLess = bAssert
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+End Function   &apos;  SFUnitTests.SF_UnitTest.AssertLess
+
+REM 
-----------------------------------------------------------------------------
+Public Function AssertLessEqual(Optional ByRef A As Variant _
+                                                               , Optional 
ByRef B As Variant _
+                                                               , Optional 
ByVal Message As Variant _
+                                                               ) As Boolean
+&apos;&apos;&apos;     Returns True when A is less than or equal to B.
+&apos;&apos;&apos;     To compare A and B:
+&apos;&apos;&apos;             They should have the same VarType or both be 
numeric
+&apos;&apos;&apos;             Elgible datatypes are String, Date or numeric.
+&apos;&apos;&apos;             String comparisons are case-sensitive.
+
+Dim bAssert As Boolean                 &apos;  Return value
+Const cstThisSub = &quot;UnitTest.AssertLessEqual&quot;
+Const cstSubArgs = &quot;A, B, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+       If IsMissing(A) Then A = Empty
+       If IsMissing(B) Then B = Empty
+       If IsMissing(Message) Then Message = &quot;&quot;
+       ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)     &apos;  
Unconditional !
+
+Try:
+       bAssert = _Assert(&quot;AssertLessEqual&quot;, False, A, B, Message)
+
+Finally:
+       AssertLessEqual = bAssert
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+End Function   &apos;  SFUnitTests.SF_UnitTest.AssertLessEqual
+
+REM 
-----------------------------------------------------------------------------
+Public Function AssertLike(Optional ByRef A As Variant _
+                                                               , Optional 
ByRef Pattern As Variant _
+                                                               , Optional 
ByVal Message As Variant _
+                                                               ) As Boolean
+&apos;&apos;&apos;     Returns True if string A matches a given pattern 
containing wildcards
+&apos;&apos;&apos;     Admitted wildcard are:  the &quot;?&quot; represents 
any single character
+&apos;&apos;&apos;                                                     the 
&quot;*&quot; represents zero, one, or multiple characters
+&apos;&apos;&apos;     The comparison is case-sensitive.
+
+Dim bAssert As Boolean                 &apos;  Return value
+Const cstThisSub = &quot;UnitTest.AssertLike&quot;
+Const cstSubArgs = &quot;A, Pattern, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+       If IsMissing(A) Then A = Empty
+       If IsMissing(Pattern) Then Pattern = &quot;&quot;
+       If IsMissing(Message) Then Message = &quot;&quot;
+       ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)     &apos;  
Unconditional !
+       If Not ScriptForge.SF_Utils._Validate(Pattern, &quot;Pattern&quot;, 
V_STRING) Then GoTo Catch
+
+Try:
+       bAssert = _Assert(&quot;AssertLike&quot;, True, A, Empty, Message, 
Pattern)
+
+Finally:
+       AssertLike = bAssert
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+Catch:
+       bAssert = False
+       GoTo Finally
+End Function   &apos;  SFUnitTests.SF_UnitTest.AssertLike
+
+REM 
-----------------------------------------------------------------------------
+Public Function AssertNotAlmostEqual(Optional ByRef A As Variant _
+                                                               , Optional 
ByRef B As Variant _
+                                                               , Optional 
ByVal Tolerance As Variant _
+                                                               , Optional 
ByVal Message As Variant _
+                                                               ) As Boolean
+&apos;&apos;&apos;     Returns True when A and B are numerical values and are 
not found close to each other.
+&apos;&apos;&apos;     Read about almost equality in the comments linked to 
the AssertEqual() method.
+
+Dim bAssert As Boolean                 &apos;  Return value
+Const cstTolerance = 1E-09
+Const cstThisSub = &quot;UnitTest.AssertNotAlmostEqual&quot;
+Const cstSubArgs = &quot;A, B, [Tolerance=1E-09], 
[Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+       If IsMissing(A) Then A = Empty
+       If IsMissing(B) Then B = Empty
+       If IsMissing(Tolerance) Then Tolerance = cstTolerance
+       If IsMissing(Message) Then Message = &quot;&quot;
+       ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)     &apos;  
Unconditional !
+       If Not ScriptForge.SF_Utils._Validate(Tolerance, &quot;Tolerance&quot;, 
ScriptForge.V_NUMERIC) Then GoTo Catch
+
+Try:
+       bAssert = _Assert(&quot;AssertNotAlmostEqual&quot;, False, A, B, 
Message, Tolerance)
+
+Finally:
+       AssertNotAlmostEqual = bAssert
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+Catch:
+       bAssert = False
+       GoTo Finally
+End Function   &apos;  SFUnitTests.SF_UnitTest.AssertNotAlmostEqual
+
+REM 
-----------------------------------------------------------------------------
+Public Function AssertNotEqual(Optional ByRef A As Variant _
+                                                               , Optional 
ByRef B As Variant _
+                                                               , Optional 
ByVal Message As Variant _
+                                                               ) As Boolean
+&apos;&apos;&apos;     Returns True when A and B are found unequal.
+&apos;&apos;&apos;     Read about equality in the comments linked to the 
AssertEqual() method.
+
+Dim bAssert As Boolean                 &apos;  Return value
+Const cstThisSub = &quot;UnitTest.AssertNotEqual&quot;
+Const cstSubArgs = &quot;A, B, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+       If IsMissing(A) Then A = Empty
+       If IsMissing(B) Then B = Empty
+       If IsMissing(Message) Then Message = &quot;&quot;
+       ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)     &apos;  
Unconditional !
+
+Try:
+       bAssert = _Assert(&quot;AssertNotEqual&quot;, False, A, B, Message)
+
+Finally:
+       AssertNotEqual = bAssert
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+End Function   &apos;  SFUnitTests.SF_UnitTest.AssertNotEqual
+
+REM 
-----------------------------------------------------------------------------
+Public Function AssertNotIn(Optional ByRef A As Variant _
+                                                               , Optional 
ByRef B As Variant _
+                                                               , Optional 
ByVal Message As Variant _
+                                                               ) As Boolean
+&apos;&apos;&apos;     Returns True when A, a string, is not found within B
+&apos;&apos;&apos;     B may be a 1D array, a ScriptForge dictionary or a 
string.
+&apos;&apos;&apos;     When B is an array, A may be a date or a numeric value.
+&apos;&apos;&apos;     String comparisons are case-sensitive.
+
+Dim bAssert As Boolean                 &apos;  Return value
+Const cstThisSub = &quot;UnitTest.AssertNotIn&quot;
+Const cstSubArgs = &quot;A, B, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+       If IsMissing(A) Then A = Empty
+       If IsMissing(B) Then B = Empty
+       If IsMissing(Message) Then Message = &quot;&quot;
+       ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)     &apos;  
Unconditional !
+
+Try:
+       bAssert = _Assert(&quot;AssertNotIn&quot;, False, A, B, Message)
+
+Finally:
+       AssertNotIn = bAssert
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+End Function   &apos;  SFUnitTests.SF_UnitTest.AssertNotIn
+
+REM 
-----------------------------------------------------------------------------
+Public Function AssertNotInstance(Optional ByRef A As Variant _
+                                                               , Optional 
ByRef ObjectType As Variant _
+                                                               , Optional 
ByVal Message As Variant _
+                                                               ) As Boolean
+&apos;&apos;&apos;     Returns True when A is an object instance of the class 
ObjectType or a variable of type ObjectType.
+&apos;&apos;&apos;     More details to be read under the AssertInstance() 
function.
+
+Dim bAssert As Boolean                 &apos;  Return value
+Const cstThisSub = &quot;UnitTest.AssertNotInstance&quot;
+Const cstSubArgs = &quot;A, ObjectType, 
[Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+       If IsMissing(A) Then A = Empty
+       If IsMissing(ObjectType) Then ObjectType = Empty
+       If IsMissing(Message) Then Message = &quot;&quot;
+       ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)     &apos;  
Unconditional !
+       If Not ScriptForge.SF_Utils._Validate(ObjectType, 
&quot;ObjectType&quot;, V_STRING) Then GoTo Catch
+
+Try:
+       bAssert = _Assert(&quot;AssertNotInstance&quot;, False, A, Empty, 
Message, ObjectType)
+
+Finally:
+       AssertNotInstance = bAssert
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+Catch:
+       bAssert = False
+       GoTo Finally
+End Function   &apos;  SFUnitTests.SF_UnitTest.AssertNotInstance
+
+REM 
-----------------------------------------------------------------------------
+Public Function AssertNotLike(Optional ByRef A As Variant _
+                                                               , Optional 
ByRef Pattern As Variant _
+                                                               , Optional 
ByVal Message As Variant _
+                                                               ) As Boolean
+&apos;&apos;&apos;     Returns True if A is not a string or does not match a 
given pattern containing wildcards
+&apos;&apos;&apos;     Admitted wildcard are:  the &quot;?&quot; represents 
any single character
+&apos;&apos;&apos;                                                     the 
&quot;*&quot; represents zero, one, or multiple characters
+&apos;&apos;&apos;     The comparison is case-sensitive.
+
+Dim bAssert As Boolean                 &apos;  Return value
+Const cstThisSub = &quot;UnitTest.AssertNotLike&quot;
+Const cstSubArgs = &quot;A, Pattern, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+       If IsMissing(A) Then A = Empty
+       If IsMissing(Pattern) Then Pattern = &quot;&quot;
+       If IsMissing(Message) Then Message = &quot;&quot;
+       ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)     &apos;  
Unconditional !
+       If Not ScriptForge.SF_Utils._Validate(Pattern, &quot;Pattern&quot;, 
V_STRING) Then GoTo Catch
+
+Try:
+       bAssert = _Assert(&quot;AssertNotLike&quot;, False, A, Empty, Message, 
Pattern)
+
+Finally:
+       AssertNotLike = bAssert
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+Catch:
+       bAssert = False
+       GoTo Finally
+End Function   &apos;  SFUnitTests.SF_UnitTest.AssertNotLike
+
+REM 
-----------------------------------------------------------------------------
+Public Function AssertNotNothing(Optional ByRef A As Variant _
+                                                               , Optional 
ByVal Message As Variant _
+                                                               ) As Boolean
+&apos;&apos;&apos;     Returns True except when A is an object that has the 
Nothing value
+
+Dim bAssert As Boolean                 &apos;  Return value
+Const cstThisSub = &quot;UnitTest.AssertNotNothing&quot;
+Const cstSubArgs = &quot;A, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+       If IsMissing(A) Then A = Empty
+       If IsMissing(Message) Then Message = &quot;&quot;
+       ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)     &apos;  
Unconditional !
+
+Try:
+       bAssert = _Assert(&quot;AssertNotNothing&quot;, False, A, Empty, 
Message)
+
+Finally:
+       AssertNotNothing = bAssert
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+End Function   &apos;  SFUnitTests.SF_UnitTest.AssertNotNothing
+
+REM 
-----------------------------------------------------------------------------
+Public Function AssertNotNull(Optional ByRef A As Variant _
+                                                               , Optional 
ByVal Message As Variant _
+                                                               ) As Boolean
+&apos;&apos;&apos;     Returns True except when A has the Null value
+
+Dim bAssert As Boolean                 &apos;  Return value
+Const cstThisSub = &quot;UnitTest.AssertNotNull&quot;
+Const cstSubArgs = &quot;A, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+       If IsMissing(A) Then A = Empty
+       If IsMissing(Message) Then Message = &quot;&quot;
+       ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)     &apos;  
Unconditional !
+
+Try:
+       bAssert = _Assert(&quot;AssertNotNull&quot;, False, A, Empty, Message)
+
+Finally:
+       AssertNotNull = bAssert
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+End Function   &apos;  SFUnitTests.SF_UnitTest.AssertNotNull
+
+REM 
-----------------------------------------------------------------------------
+Public Function AssertNotRegex(Optional ByRef A As Variant _
+                                                               , Optional 
ByRef Regex As Variant _
+                                                               , Optional 
ByVal Message As Variant _
+                                                               ) As Boolean
+&apos;&apos;&apos;     Returns True when A is not a string or does not match 
the given regular expression.
+&apos;&apos;&apos;     The comparison is case-sensitive.
+
+Dim bAssert As Boolean                 &apos;  Return value
+Const cstThisSub = &quot;UnitTest.AssertNotRegex&quot;
+Const cstSubArgs = &quot;A, Regex, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+       If IsMissing(A) Then A = Empty
+       If IsMissing(Regex) Then Regex = &quot;&quot;
+       If IsMissing(Message) Then Message = &quot;&quot;
+       ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)     &apos;  
Unconditional !
+       If Not ScriptForge.SF_Utils._Validate(Regex, &quot;Regex&quot;, 
V_STRING) Then GoTo Catch
+
+Try:
+       bAssert = _Assert(&quot;AssertNotRegex&quot;, False, A, Empty, Message, 
Regex)
+
+Finally:
+       AssertNotRegex = bAssert
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+Catch:
+       bAssert = False
+       GoTo Finally
+End Function   &apos;  SFUnitTests.SF_UnitTest.AssertNotRegex
+
+REM 
-----------------------------------------------------------------------------
+Public Function AssertRegex(Optional ByRef A As Variant _
+                                                               , Optional 
ByRef Regex As Variant _
+                                                               , Optional 
ByVal Message As Variant _
+                                                               ) As Boolean
+&apos;&apos;&apos;     Returns True when string A matches the given regular 
expression.
+&apos;&apos;&apos;     The comparison is case-sensitive.
+
+Dim bAssert As Boolean                 &apos;  Return value
+Const cstThisSub = &quot;UnitTest.AssertRegex&quot;
+Const cstSubArgs = &quot;A, Regex, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+       If IsMissing(A) Then A = Empty
+       If IsMissing(Regex) Then Regex = &quot;&quot;
+       If IsMissing(Message) Then Message = &quot;&quot;
+       ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)     &apos;  
Unconditional !
+       If Not ScriptForge.SF_Utils._Validate(Regex, &quot;Regex&quot;, 
V_STRING) Then GoTo Catch
+
+Try:
+       bAssert = _Assert(&quot;AssertRegex&quot;, True, A, Empty, Message, 
Regex)
+
+Finally:
+       AssertRegex = bAssert
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+Catch:
+       bAssert = False
+       GoTo Finally
+End Function   &apos;  SFUnitTests.SF_UnitTest.AssertRegex
+
+REM 
-----------------------------------------------------------------------------
+Public Function AssertTrue(Optional ByRef A As Variant _
+                                                               , Optional 
ByVal Message As Variant _
+                                                               ) As Boolean
+&apos;&apos;&apos;     Returns True when A is a Boolean and its value is True
+
+Dim bAssert As Boolean                 &apos;  Return value
+Const cstThisSub = &quot;UnitTest.AssertTrue&quot;
+Const cstSubArgs = &quot;A, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+       If IsMissing(A) Then A = Empty
+       If IsMissing(Message) Then Message = &quot;&quot;
+       ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)     &apos;  
Unconditional !
+
+Try:
+       bAssert = _Assert(&quot;AssertTrue&quot;, True, A, Empty, Message)
+
+Finally:
+       AssertTrue = bAssert
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+End Function   &apos;  SFUnitTests.SF_UnitTest.AssertTrue
+
+REM 
-----------------------------------------------------------------------------
+Public Sub Fail(Optional ByVal Message As Variant)
+&apos;&apos;&apos;     Forces a test failure
+&apos;&apos;&apos;     Args:
+
+
+Dim bAssert As Boolean                 &apos;  Fictive return value
+Const cstThisSub = &quot;UnitTest.Fail&quot;
+Const cstSubArgs = &quot;[Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+       If IsMissing(Message) Then Message = &quot;&quot;
+       ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)     &apos;  
Unconditional !
+
+Try:
+       bAssert = _Assert(&quot;Fail&quot;, False, Empty, Empty, Message)
+
+Finally:
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Sub
+End Sub        &apos;  SFUnitTests.SF_UnitTest.Fail
+
+REM 
-----------------------------------------------------------------------------
+Public Sub Log(Optional ByVal Message As Variant)
+&apos;&apos;&apos;     Forces a test Logure
+
+Dim bAssert As Boolean                 &apos;  Fictive return value
+Dim bVerbose As Boolean                        :       bVerbose = _Verbose
+Const cstThisSub = &quot;UnitTest.Log&quot;
+Const cstSubArgs = &quot;[Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+       If IsMissing(Message) Then Message = &quot;&quot;
+       ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)     &apos;  
Unconditional !
+
+Try:
+       &apos;  Force the display of the message in the console
+       _Verbose = True
+       bAssert = _Assert(&quot;Log&quot;, True, Empty, Empty, Message)
+       _Verbose = bVerbose
+
+Finally:
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Sub
+End Sub        &apos;  SFUnitTests.SF_UnitTest.Log
+
+REM 
-----------------------------------------------------------------------------
+Public Function GetProperty(Optional ByVal PropertyName As Variant) As Variant
+&apos;&apos;&apos;     Return the actual value of the given property
+&apos;&apos;&apos;     Args:
+&apos;&apos;&apos;             PropertyName: the name of the property as a 
string
+&apos;&apos;&apos;     Returns:
+&apos;&apos;&apos;             The actual value of the property
+&apos;&apos;&apos;     Exceptions
+&apos;&apos;&apos;             ARGUMENTERROR           The property does not 
exist
+&apos;&apos;&apos;     Examples:
+&apos;&apos;&apos;             myUnitTest.GetProperty(&quot;Duration&quot;)
+
+Const cstThisSub = &quot;UnitTest.GetProperty&quot;
+Const cstSubArgs = &quot;PropertyName&quot;
+
+       If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+       GetProperty = Null
+
+Check:
+       If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+               If Not ScriptForge.SF_Utils._Validate(PropertyName, 
&quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
+       End If
+
+Try:
+       GetProperty = _PropertyGet(PropertyName)
+
+Finally:
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+Catch:
+       GoTo Finally
+End Function   &apos;  SFUnitTests.SF_UnitTest.Properties
+
+REM 
-----------------------------------------------------------------------------
+Public Function Methods() As Variant
+&apos;&apos;&apos;     Return the list or methods of the UnitTest class as an 
array
+
+       Methods = Array( _
+                                       &quot;AssertAlmostEqual&quot; _
+                                       , &quot;AssertEqual&quot; _
+                                       , &quot;AssertFalse&quot; _
+                                       , &quot;AssertGreater&quot; _
+                                       , &quot;AssertGreaterEqual&quot; _
+                                       , &quot;AssertIn&quot; _
+                                       , &quot;AssertIsInstance&quot; _
+                                       , &quot;AssertIsNothing&quot; _
+                                       , &quot;AssertLike&quot; _
+                                       , &quot;AssertNotRegex&quot; _
+                                       , &quot;AssertIsNull&quot; _
+                                       , &quot;AssertLess&quot; _
+                                       , &quot;AssertLessEqual&quot; _
+                                       , &quot;AssertNotAlmostEqual&quot; _
+                                       , &quot;AssertNotEqual&quot; _
+                                       , &quot;AssertNotIn&quot; _
+                                       , &quot;AssertNotInstance&quot; _
+                                       , &quot;AssertNotLike&quot; _
+                                       , &quot;AssertNotNothing&quot; _
+                                       , &quot;AssertNotNull&quot; _
+                                       , &quot;AssertRegex&quot; _
+                                       , &quot;AssertTrue&quot; _
+                                       , &quot;Fail&quot; _
+                                       , &quot;Log&quot; _
+                                       , &quot;RunTest&quot; _
+                                       , &quot;SkipTest&quot; _
+                                       )
+
+End Function   &apos;  SFUnitTests.SF_UnitTest.Methods
+
+REM 
-----------------------------------------------------------------------------
+Public Function Properties() As Variant
+&apos;&apos;&apos;     Return the list or properties of the UnitTest class as 
an array
+
+       Properties = Array( _
+                                       &quot;LongMessage&quot; _
+                                       , &quot;ReturnCode&quot; _
+                                       , &quot;Verbose&quot; _
+                                       , &quot;WhenAssertionFails&quot; _
+                                       )
+
+End Function   &apos;  SFUnitTests.SF_UnitTest.Properties
+
+REM 
-----------------------------------------------------------------------------
+Public Sub ReportError(Optional ByVal Message As Variant)
+&apos;&apos;&apos;     DIsplay a message box with the current property values 
of the &quot;Exception&quot; service.
+&apos;&apos;&apos;     Depending on the WhenAssertionFails property, a Raise() 
or RaiseWarning()
+&apos;&apos;&apos;     is issued. The Raise() method stops completely the 
Basic running process.
+&apos;&apos;&apos;     The ReportError() method is presumed present in a user 
script in an error
+&apos;&apos;&apos;     handling part of the actual testcase.
+&apos;&apos;&apos;     Args:
+&apos;&apos;&apos;             Message: a string to replace or to complete the 
standard message description
+&apos;&apos;&apos;     Example:
+&apos;&apos;&apos;             See the Test_ArraySize() sub in the 
module&apos;s heading example
+
+Dim sLine As String                            &apos;  Line number where the 
error occurred
+Dim sError As String                   &apos;  Exception description
+Dim sErrorCode As String               &apos;  Exception number
+Const cstThisSub = &quot;UnitTest.ReportError&quot;
+Const cstSubArgs = &quot;[Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+       If IsMissing(Message) Or IsEmpty(Message) Then Message = &quot;&quot;
+       ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)     &apos;  
Unconditional !
+       If VarType(Message) &lt;&gt; V_STRING Then Message = &quot;&quot;
+
+Try:
+       sLine = &quot;ln &quot; &amp; CStr(Exception.Source)
+       If _ExecutionMode = FULLMODE Then sLine = _Module &amp; &quot;.&quot; 
&amp; _TestCase &amp; &quot; &quot; &amp; sLine
+       If Len(Message) &gt; 0 Then
+               sError = Message
+       Else
+               If Exception.Number = INVALIDPROCEDURECALL Then
+                       sError = &quot;Test case failure&quot;
+                       sErrorCode = &quot;ASSERTIONFAILED&quot;
+               Else
+                       sError = Exception.Description
+                       sErrorCode = CStr(Exception.Number)
+               End If
+       End If
+
+       Select Case _WhenAssertionFails
+               Case FAILIGNORE
+               Case FAILSTOPSUITE
+                       Exception.RaiseWarning(sErrorCode, sLine, sError)
+               Case FAILIMMEDIATESTOP
+                       Exception.Raise(sErrorCode, sLine, sError)
+       End Select
+
+Finally:
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Sub
+End Sub                        &apos;  SFUnitTests.SF_UnitTest.ReportError
+REM 
-----------------------------------------------------------------------------
+Public Function RunTest(Optional ByVal TestSuite As Variant _
+                                                       , Optional ByVal 
TestCasePattern As Variant _
+                                                       , Optional ByVal 
Message As Variant _
+                                                       ) As Integer
+&apos;&apos;&apos;     Execute a test suite pointed out by a module name.
+&apos;&apos;&apos;     Each test case will be run independently from each 
other.
+&apos;&apos;&apos;     The names of the test cases to be run may be selected 
with a string pattern.
+&apos;&apos;&apos;     The test is &quot;orchestrated&quot; by this method:
+&apos;&apos;&apos;             1. Execute the optional Setup() method present 
in the module
+&apos;&apos;&apos;             2. Execute once each test case, in any order
+&apos;&apos;&apos;             3, Execute the optional TearDown() method 
present in the module
+&apos;&apos;&apos;     Args:
+&apos;&apos;&apos;             TestSuite: the name of the module containing 
the set of test cases to run
+&apos;&apos;&apos;             TestCasePattern: the pattern that the test 
cases must match. The comparison is not case-sensitive.
+&apos;&apos;&apos;                     Non-matching finctions and subs are 
ignored.
+&apos;&apos;&apos;                     Admitted wildcard are:  the 
&quot;?&quot; represents any single character
+&apos;&apos;&apos;                                                             
        the &quot;*&quot; represents zero, one, or multiple characters
+&apos;&apos;&apos;                     The default pattern is 
&quot;Test_*&quot;
+&apos;&apos;&apos;             Message: the message to be displayed in the 
console when the test starts.
+&apos;&apos;&apos;     Returns:
+&apos;&apos;&apos;             The return code of the esecution (RCxxx 
constants
+&apos;&apos;&apos;     Examples:
+&apos;&apos;&apos;             
GlobalScope.BasicLibraries.loadLibrary(&quot;ScriptForge&quot;)
+&apos;&apos;&apos;             Dim test        :       test = 
CreateScriptService(&quot;UnitTest&quot;, ThisComponent, &quot;Tests&quot;)
+&apos;&apos;&apos;             test.RunTest(&quot;AllTests&quot;)      &apos;  
AllTests is a module name ; test cases are named &quot;Test_*&quot; (default)
+
+Dim iRun As Integer                                    &apos;  Return value
+Dim sRunMessage As String                      &apos;  Reporting
+Dim iModule    As Integer                              &apos;  Index of module 
currently running
+Dim vMethods As Variant                                &apos;  Set of methods
+Dim sMethod As String                          &apos;  A single method
+Dim iMethod As Integer                         &apos;  Index in MethodNames
+Dim m As Integer
+
+Const cstThisSub = &quot;UnitTest.RunTest&quot;
+Const cstSubArgs = &quot;TestSuite, 
[TestCasePattern=&quot;&quot;Test_*&quot;&quot;], 
[Message=&quot;&quot;&quot;&quot;]&quot;
+
+       iRun = RCNORMALEND
+       If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+       If IsMissing(TestCasePattern) Or IsEmpty(TestCasePattern) Then 
TestCasePattern = &quot;Test_*&quot;
+       If IsMissing(Message) Or IsEmpty(Message) Then Message = &quot;&quot;
+       ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)     &apos;  
Unconditional !
+       If Not ScriptForge.SF_Utils._Validate(TestSuite, &quot;TestSuite&quot;, 
V_STRING, ModuleNames) Then GoTo Catch
+       If Not ScriptForge.SF_Utils._Validate(TestCasePattern, 
&quot;TestCasePattern&quot;, V_STRING) Then GoTo Catch
+       If Not ScriptForge.SF_Utils._Validate(Message, &quot;Message&quot;, 
V_STRING) Then GoTo Catch
+
+       &apos;  A RunTest() is forbidden inside a test suite or when simple mode
+       If _Status &lt;&gt; STATUSSTANDBY Or _ExecutionMode &lt;&gt; FULLMODE 
Then GoTo CatchMethod
+
+       &apos;  Ignore any call when an abnormal end has been encountered
+       If _ReturnCode = RCABORTTEST Then GoTo Catch
+
+Try:
+       iModule = ScriptForge.SF_Array.IndexOf(ModuleNames, TestSuite, 
CaseSensitive := False, SortOrder := &quot;ASC&quot;)
+       _Module = ModuleNames(iModule)
+
+       &apos;  Start timer
+       If Not IsNull(SuiteTimer) Then SuiteTimer = SuiteTimer.Dispose()
+       Set SuiteTimer = CreateScriptService(&quot;ScriptForge.Timer&quot;, 
True)
+
+       &apos;  Report the start of a new test suite
+       sRunMessage =  &quot;RUNTEST ENTER testsuite=&apos;&quot; &amp; 
LibraryName &amp; &quot;.&quot; &amp; _Module &amp; &quot;&apos;, 
pattern=&apos;&quot; &amp; TestCasePattern &amp; &quot;&apos;&quot;
+       _ReportMessage(sRunMessage, Message)
+       _Status = STATUSSUITESTARTED
+
+       &apos;  Collect all the methods of the module
+       If Modules(iModule).hasChildNodes() Then
+               vMethods = Modules(iModule).getChildNodes()
+               MethodNames = Array()
+               For m = 0 To UBound(vMethods)
+                       sMethod = vMethods(m).getName()
+                       MethodNames = ScriptForge.SF_Array.Append(MethodNames, 
sMethod)
+               Next m
+       End If
+
+       &apos;  Execute the Setup() method, if it exists
+       iMethod = ScriptForge.SF_Array.IndexOf(MethodNames, &quot;Setup&quot;, 
CaseSensitive := False, SortOrder := &quot;ASC&quot;)
+       If iMethod &gt;= 0 Then
+               _TestCase = MethodNames(iMethod)        &apos;  _TestCase is 
used in ReportError()
+               If Not _ExecuteScript(_TestCase) Then GoTo Catch
+       End If
+
+       &apos;  Execute the test cases that match the pattern
+       For iMethod = 0 To UBound(MethodNames)
+               If _ReturnCode = RCSKIPTEST Or _ReturnCode = RCASSERTIONFAILED 
Then Exit For
+               sMethod = MethodNames(iMethod)
+               If ScriptForge.SF_String.IsLike(sMethod, TestCasePattern, 
CaseSensitive := False) Then
+                       _TestCase = sMethod
+                       &apos;  Start timer
+                       If Not IsNull(CaseTimer) Then CaseTimer = 
CaseTimer.Dispose()
+                       Set CaseTimer = 
CreateScriptService(&quot;ScriptForge.Timer&quot;, True)
+                       If Not _ExecuteScript(sMethod) Then GoTo Catch
+                       CaseTimer.Terminate()
+                       _TestCase = &quot;&quot;
+               End If
+       Next iMethod
+
+       If _ReturnCode &lt;&gt; RCSKIPTEST Then
+               &apos;  Execute the TearDown() method, if it exists
+               iMethod = ScriptForge.SF_Array.IndexOf(MethodNames, 
&quot;TearDown&quot;, CaseSensitive := False, SortOrder := &quot;ASC&quot;)
+               If iMethod &gt;= 0 Then
+                       _TestCase = MethodNames(iMethod)        &apos;  
_TestCase is used in ReportError()
+                       If Not _ExecuteScript(_TestCase) Then GoTo Catch
+               End If
+       End If
+
+       &apos;  Report the end of the current test suite
+       sRunMessage = &quot;RUNTEST EXIT testsuite=&apos;&quot; &amp; 
LibraryName &amp; &quot;.&quot; &amp; _Module &amp; &quot;&apos; &quot; &amp; 
_Duration(&quot;Suite&quot;, True)
+       _ReportMessage(sRunMessage, Message)
+
+       &apos;  Stop timer
+       SuiteTimer.Terminate()
+
+       &apos;  Housekeeping
+       MethodNames = Array()
+       _Module = &quot;&quot;
+       _Status = STATUSSTANDBY
+
+Finally:
+       _ReturnCode = iRun
+       RunTest = iRun
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+Catch:
+       iRun = RCABORTTEST
+       GoTo Finally
+CatchMethod:
+       ScriptForge.SF_Exception.RaiseFatal(UNITTESTMETHODERROR, 
&quot;RunTest&quot;)
+       GoTo Catch
+End Function   &apos;  SFUnitTests.SF_UnitTest.RunTest
+
+REM 
-----------------------------------------------------------------------------
+Public Function SetProperty(Optional ByVal PropertyName As Variant _
+                                                               , Optional 
ByRef Value As Variant _
+                                                               ) As Boolean
+&apos;&apos;&apos;     Set a new value to the given property
+&apos;&apos;&apos;     Args:
+&apos;&apos;&apos;             PropertyName: the name of the property as a 
string
+&apos;&apos;&apos;             Value: its new value
+&apos;&apos;&apos;     Exceptions
+&apos;&apos;&apos;             ARGUMENTERROR           The property does not 
exist
+
+Const cstThisSub = &quot;UnitTest.SetProperty&quot;
+Const cstSubArgs = &quot;PropertyName, Value&quot;
+
+       If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+       SetProperty = False
+
+Check:
+       If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+               If Not ScriptForge.SF_Utils._Validate(PropertyName, 
&quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
+       End If
+
+Try:
+       SetProperty = _PropertySet(PropertyName, Value)
+
+Finally:
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+Catch:
+       GoTo Finally
+End Function   &apos;  SFUnitTests.SF_UnitTest.SetProperty
+
+REM 
-----------------------------------------------------------------------------
+Public Function SkipTest(Optional ByVal Message As Variant) As Boolean
+&apos;&apos;&apos;     Interrupt the running test suite. The TearDown() method 
is NOT executed.
+&apos;&apos;&apos;     The SkipTest() method is normally meaningful only in a 
Setup() method when not all the
+&apos;&apos;&apos;     conditions to run the test are met.
+&apos;&apos;&apos;     It is up to the Setup() script to exit shortly after 
the SkipTest() call..
+&apos;&apos;&apos;     The method may also be executed in a test case. Next 
test cases will not be executed.
+&apos;&apos;&apos;     Remember however that the test cases are executed is an 
arbitrary order.
+&apos;&apos;&apos;     Args:
+&apos;&apos;&apos;             Message: the message to be displayed in the 
console
+&apos;&apos;&apos;     Returns:
+&apos;&apos;&apos;             The return code of the esecution (RCxxx 
constants
+&apos;&apos;&apos;     Examples:
+&apos;&apos;&apos;             
GlobalScope.BasicLibraries.loadLibrary(&quot;ScriptForge&quot;)
+&apos;&apos;&apos;             Dim test        :       test = 
CreateScriptService(&quot;UnitTest&quot;, ThisComponent, &quot;Tests&quot;)
+&apos;&apos;&apos;             test.SkipTest(&quot;AllTests&quot;)     &apos;  
AllTests is a module name ; test cases are named &quot;Test_*&quot; (default)
+
+Dim bSkip As Boolean                           &apos;  Return value
+Dim sSkipMessage As String                     &apos;  Reporting
+
+Const cstThisSub = &quot;UnitTest.SkipTest&quot;
+Const cstSubArgs = &quot;[Message=&quot;&quot;&quot;&quot;]&quot;
+
+       bSkip = False
+       If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+       If IsMissing(Message) Or IsEmpty(Message) Then Message = &quot;&quot;
+       ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)     &apos;  
Unconditional !
+       If Not ScriptForge.SF_Utils._Validate(Message, &quot;Message&quot;, 
V_STRING) Then GoTo Catch
+
+       &apos;  A SkipTest() is forbidden when simple mode
+       If _ExecutionMode &lt;&gt; FULLMODE Then GoTo CatchMethod
+
+       &apos;  Ignore any call when an abnormal end has been encountered
+       If _ReturnCode = RCABORTTEST Then GoTo Catch
+
+Try:
+       If _Status = STATUSSETUP Or _Status = STATUSTESTCASE Then
+               _ReturnCode = RCSKIPTEST
+               bSkip = True
+               &apos;  Exit message
+               sSkipMessage = _Duration(&quot;Test&quot;, True) &amp; 
&quot;SKIPTEST TESTSUITE=&apos;&quot; &amp; _Module &amp; &quot;&apos;&quot;
+               _ReportMessage(sSkipMessage, Message)
+       End If
+
+Finally:
+       SkipTest = bSkip
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+Catch:
+       _ReturnCode = RCABORTTEST
+       GoTo Finally
+CatchMethod:
+       ScriptForge.SF_Exception.RaiseFatal(UNITTESTMETHODERROR, 
&quot;SkipTest&quot;)
+       GoTo Catch
+End Function   &apos;  SFUnitTests.SF_UnitTest.SkipTest
+
+REM =========================================================== PRIVATE 
FUNCTIONS
+
+REM 
-----------------------------------------------------------------------------
+Private Function _Assert(ByVal psAssert As String _
+                                                       , ByVal pvReturn As 
Variant _
+                                                       , ByRef A As Variant _
+                                                       , ByRef B As Variant _
+                                                       , Optional ByVal 
pvMessage As Variant _
+                                                       , Optional ByVal pvArg 
As Variant _
+                                                       ) As Boolean
+&apos;&apos;&apos;     Evaluation of the assertion and management of the 
success or the failure
+&apos;&apos;&apos;     Args:
+&apos;&apos;&apos;             psAssert: the assertion verb as a string
+&apos;&apos;&apos;             pvReturn: may be True, False or Empty
+&apos;&apos;&apos;                     When True (resp. False), the assertion 
must be evaluated as True (resp. False)
+&apos;&apos;&apos;                             e.g.    AssertEqual() will call 
_Assert(&quot;AssertEqual&quot;, True, ...)
+&apos;&apos;&apos;                                             
AssertNotEqual() will call _Assert(&quot;AssertNotEqual&quot;, False, ...)
+&apos;&apos;&apos;                     Empty may be used for recursive calls 
of the function (for comparing arrays, ...)
+&apos;&apos;&apos;             A: always present
+&apos;&apos;&apos;             B: may be empty
+&apos;&apos;&apos;             pvMessage: the message to display on the console
+&apos;&apos;&apos;             pvArg: optional additional argument of the 
assert function
+&apos;&apos;&apos;     Returns:
+&apos;&apos;&apos;             True when success
+
+Dim bAssert As Boolean                 &apos;  Return value
+Dim bEval As Boolean                   &apos;  To be compared with pvReturn
+Dim iVarTypeA As Integer               &apos;  Alias of _VarTypeExt(A)
+Dim iVarTypeB As Integer               &apos;  Alias of _VarTypeExt(B)
+Dim oVarTypeObjA As Object             &apos;  SF_Utils.ObjectDescriptor
+Dim oVarTypeObjB As Object             &apos;  SF_Utils.ObjectDescriptor
+Dim oUtils As Object                   :       Set oUtils = 
ScriptForge.SF_Utils
+Dim iDims As Integer                   &apos;  Number of dimensions of array
+Dim oAliasB As Object                  &apos;  Alias of B to bypass the 
&quot;Object variable not set&quot; issue
+Dim dblA As Double                             &apos;  Alias of A
+Dim dblB As Double                             &apos;  Alias of B
+Dim dblTolerance As Double             &apos;  Alias of pvArg
+Dim oString As Object                  :       Set oString = 
ScriptForge.SF_String
+Dim sArgName As String                 &apos;  Argument description
+Dim i As Long, j As Long
+
+Check:
+       bAssert = False
+       If IsMissing(pvMessage) Then pvMessage = &quot;&quot;
+       If Not oUtils._Validate(pvMessage, &quot;Message&quot;, V_STRING) Then 
GoTo Finally
+       If IsMissing(pvArg) Then pvArg = &quot;&quot;
+
+Try:
+       iVarTypeA = oUtils._VarTypeExt(A)
+       iVarTypeB = oUtils._VarTypeExt(B)
+       sArgName = &quot;&quot;
+
+       Select Case UCase(psAssert)
+               Case UCase(&quot;AssertAlmostEqual&quot;), 
UCase(&quot;AssertNotAlmostEqual&quot;)
+                       bEval = ( iVarTypeA = iVarTypeB And iVarTypeA = 
ScriptForge.V_NUMERIC )
+                       If bEval Then
+                               dblA = CDbl(A)
+                               dblB = CDbl(B)
+                               dblTolerance = Abs(CDbl(pvArg))
+                               bEval = ( Abs(dblA - dblB) &lt;= (dblTolerance 
* Iif(Abs(dblA) &gt; Abs(DblB), Abs(dblA), Abs(dblB))) )
+                       End If
+               Case UCase(&quot;AssertEqual&quot;), 
UCase(&quot;AssertNotEqual&quot;)
+                       If Not IsArray(A) Then
+                               bEval = ( iVarTypeA = iVarTypeB )
+                               If bEval Then
+                                       Select Case iVarTypeA
+                                               Case V_EMPTY, V_NULL
+                                               Case V_STRING
+                                                       bEval = ( StrComp(A, B, 
1) = 0 )
+                                               Case ScriptForge.V_NUMERIC, 
ScriptForge.V_BOOLEAN
+                                                       bEval = ( A = B )
+                                               Case V_DATE
+                                                       bEval = ( 
Abs(DateDiff(&quot;s&quot;, A, B)) = 0 )
+                                               Case ScriptForge.V_OBJECT
+                                                       Set oVarTypeObjA = 
oUtils._VarTypeObj(A)
+                                                       Set oVarTypeObjB = 
oUtils._VarTypeObj(B)
+                                                       bEval = ( 
oVarTypeObjA.iVarType = oVarTypeObjB.iVarType )
+                                                       If bEval Then
+                                                               Select Case 
oVarTypeObjA.iVarType
+                                                                       Case 
ScriptForge.V_NOTHING
+                                                                       Case 
ScriptForge.V_UNOOBJECT
+                                                                               
bEval = EqualUnoObjects(A, B)
+                                                                       Case 
ScriptForge.V_SFOBJECT, ScriptForge.V_BASICOBJECT
+                                                                               
bEval = False
+                                                               End Select
+                                                       End If
+                                       End Select
+                               End If
+                       Else    &apos;  Compare arrays
+                               bEval = IsArray(B)
+                               If bEval Then
+                                       iDims = 
ScriptForge.SF_Array.CountDims(A)
+                                       bEval = ( iDims = 
ScriptForge.SF_Array.CountDims(B) And iDims &lt;= 2 )
+                                       If bEval Then
+                                               Select Case iDims
+                                                       Case -1, 0              
&apos;  Scalars (not possible) or empty arrays
+                                                       Case 1                  
&apos;  1D array
+                                                               bEval = ( 
LBound(A) = LBound(B) And UBound(A) = UBound(B) )
+                                                               If bEval Then
+                                                                       For i = 
LBound(A) To UBound(A)
+                                                                               
bEval = _Assert(psAssert, Empty, A(i), B(i))
+                                                                               
If Not bEval Then Exit For
+                                                                       Next i
+                                                               End If
+                                                       Case 2                  
&apos;  2D array
+                                                               bEval = ( 
LBound(A, 1) = LBound(B, 1) And UBound(A, 1) = UBound(B, 1) _
+                                                                               
And LBound(A, 2) = LBound(B, 2) And UBound(A, 2) = UBound(B, 2) )
+                                                               If bEval Then
+                                                                       For i = 
LBound(A, 1) To UBound(A, 1)
+                                                                               
For j = LBound(A, 2) To UBound(A, 2)
+                                                                               
        bEval = _Assert(psAssert, Empty, A(i, j), B(i, j))
+                                                                               
        If Not bEval Then Exit For
+                                                                               
Next j
+                                                                               
If Not bEval Then Exit For
+                                                                       Next i
+                                                               End If
+                                               End Select
+                                       End If
+                               End If
+                       End If
+               Case UCase(&quot;AssertFalse&quot;)
+                       If iVarTypeA = ScriptForge.V_BOOLEAN Then bEval = Not A 
Else bEval = False
+               Case UCase(&quot;AssertGreater&quot;), 
UCase(&quot;AssertLessEqual&quot;)
+                       bEval = ( iVarTypeA = iVarTypeB _
+                                               And (iVarTypeA = 
ScriptForge.V_NUMERIC Or iVarTypeA = V_STRING Or iVarTypeA = V_DATE) )
+                       If bEval Then bEval = ( A &gt; B )
+               Case UCase(&quot;AssertGreaterEqual&quot;), 
UCase(&quot;AssertLess&quot;)
+                       bEval = ( iVarTypeA = iVarTypeB _
+                                               And (iVarTypeA = 
ScriptForge.V_NUMERIC Or iVarTypeA = V_STRING Or iVarTypeA = V_DATE) )
+                       If bEval Then bEval = ( A &gt;= B )
+               Case UCase(&quot;AssertIn&quot;), UCase(&quot;AssertNotIn&quot;)
+                       Set oVarTypeObjB = oUtils._VarTypeObj(B)
+                       Select Case True
+                               Case iVarTypeA = V_STRING And iVarTypeB = 
V_STRING
+                                       bEval = ( Len(A) &gt; 0 And Len(B) &gt; 
0 )
+                                       If bEval Then bEval = ( InStr(1, B, A, 
0) &gt; 0 )
+                               Case (iVarTypeA = V_DATE Or iVarTypeA = 
V_STRING Or iVarTypeA = ScriptForge.V_NUMERIC) _
+                                               And iVarTypeB &gt;= 
ScriptForge.V_ARRAY
+                                       bEval = ( 
ScriptForge.SF_Array.CountDims(B) = 1 )
+                                       If bEval Then bEval = 
ScriptForge.SF_Array.Contains(B, A, CaseSensitive := True)
+                               Case oVarTypeObjB.iVarType = 
ScriptForge.V_SFOBJECT And oVarTypeObjB.sObjectType = &quot;DICTIONARY&quot;
+                                       bEval = ( Len(A) &gt; 0 )
+                                       If bEval Then
+                                               Set oAliasB = B
+                                               bEval = 
ScriptForge.SF_Array.Contains(oAliasB.Keys(), A, CaseSensitive := True)
+                                       End If
+                               Case Else
+                                       bEval = False
+                       End Select
+               Case UCase(&quot;AssertIsInstance&quot;), 
UCase(&quot;AssertNotInstance&quot;)
+                       Set oVarTypeObjA = oUtils._VarTypeObj(A)
+                       sArgName = &quot;ObjectType&quot;
+                       With oVarTypeObjA
+                               Select Case .iVarType
+                                       Case ScriptForge.V_UNOOBJECT
+                                               bEval = ( pvArg = .sObjectType )
+                                       Case ScriptForge.V_SFOBJECT
+                                               bEval = ( UCase(pvArg) = 
UCase(.sObjectType) Or UCase(pvArg) = &quot;SF_&quot; &amp; UCase(.sObjectType) 
_
+                                                                       Or 
UCase(pvArg) = UCase(.sServiceName) )
+                                       Case ScriptForge.V_NOTHING, 
ScriptForge.V_BASICOBJECT
+                                               bEval = False
+                                       Case &gt;= ScriptForge.V_ARRAY
+                                               bEval = ( UCase(pvArg) = 
&quot;ARRAY&quot; )
+                                       Case Else
+                                               bEval = ( UCase(TypeName(A)) = 
UCase(pvArg) )
+                               End Select
+                       End With
+               Case UCase(&quot;AssertIsNothing&quot;), 
UCase(&quot;AssertNotNothing&quot;)
+                       bEval = ( iVarTypeA = ScriptForge.V_OBJECT )
+                       If bEval Then bEval = ( A Is Nothing )
+               Case UCase(&quot;AssertIsNull&quot;), 
UCase(&quot;AssertNotNull&quot;)
+                       bEval = ( iVarTypeA = V_NULL )
+               Case UCase(&quot;AssertLike&quot;), 
UCase(&quot;AssertNotLike&quot;)
+                       sArgName = &quot;Pattern&quot;
+                       bEval = ( iVarTypeA = V_STRING And Len(pvArg) &gt; 0 )
+                       If bEval Then bEval = oString.IsLike(A, pvArg, 
CaseSensitive := True)
+               Case UCase(&quot;AssertRegex&quot;), 
UCase(&quot;AssertNotRegex&quot;)
+                       sArgName = &quot;Regex&quot;
+                       bEval = ( iVarTypeA = V_STRING And Len(pvArg) &gt; 0 )
+                       If bEval Then bEval = oString.IsRegex(A, pvArg, 
CaseSensitive := True)
+               Case UCase(&quot;AssertTrue&quot;)
+                       If iVarTypeA = ScriptForge.V_BOOLEAN Then bEval = A 
Else bEval = False
+               Case UCase(&quot;FAIL&quot;), UCase(&quot;Log&quot;)
+                       bEval = True
+               Case Else
+       End Select
+
+       &apos;  Check the result of the assertion vs. what it should be
+       If IsEmpty(pvReturn) Then
+               bAssert = bEval         &apos;  Recursive call =&gt; Reporting 
and failure management are done by calling _Assert() procedure
+       Else    &apos;  pvReturn is Boolean =&gt; Call from user script
+               bAssert = Iif(pvReturn, bEval, Not bEval)
+               &apos;  Report the assertion evaluation
+               If _Verbose Or Not bAssert Then
+                       _ReportMessage(&quot;    &quot; &amp; psAssert _
+                                                       &amp; Iif(IsEmpty(A), 
&quot;&quot;, &quot; = &quot; &amp; bAssert &amp; &quot;, A = &quot; &amp; 
oUtils._Repr(A)) _
+                                                       &amp; Iif(IsEmpty(B), 
&quot;&quot;, &quot;, B = &quot; &amp; oUtils._Repr(B)) _
+                                                       &amp; Iif(Len(sArgName) 
= 0, &quot;&quot;, &quot;, &quot; &amp; sArgName &amp; &quot; = &quot; &amp; 
pvArg) _
+                                                       , pvMessage)
+               End If
+               &apos;  Manage assertion failure
+               If Not bAssert Then
+                       _FailedAssert = psAssert
+                       Select Case _WhenAssertionFails
+                               Case FAILIGNORE                 &apos;  Do 
nothing
+                               Case Else
+                                       _ReturnCode = RCASSERTIONFAILED
+                                       &apos;  Cause artificially a run-time 
error
+                                       Dim STRINGBADUSE As String
+
+                                       
&apos;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+                                       &apos;+ To avoid a run-time error on 
next executable statement,                                         +
+                                       &apos;+ insert an error handler in the 
code of your test case:                                          +
+                                       &apos;+ Like in next code:              
                                                                                
                        +
+                                       &apos;+         On Local Error GoTo 
Catch                                                                           
                    +
+                                       &apos;+         ...                     
                                                                                
                                        +

... etc. - the rest is truncated

Reply via email to