Computer Scientist

Tuesday, 9 January 2018

Python unittest: everything needed to work

Unit test is essential for each project, even though it would be ignored when the project was getting time restrained. Here the basic steps are listed in the following sections to illustrate the usage of unittest module for Python project:

Test theory:

  • Test fixture: this is the test preparation before tests and any associated cleanup actions.
  • Test case: this is the most fundamental test unit.
  • Test suite: this is a collection of test cases and/or test suites.
  • Test runner: this is the most outer part of the test system, is used to orchestrate the execution of tests and to provide the outcomes to the user.
Here is the potential structure of these components in a project:

How to run unittest from command-line?

Here is an example of running unittest from command-line for the project Lux: 

python -m unittest discover -s tests -p . -f -v

This will be explained in more details with further more options.

-m: run the 'unittest' library module as a script. 
-v: verbose
-f (--failfast): stop the test run on the first error or failure.
-b (--buffer): stdout and stderr streams are bufferred during the test run. It will be discarded for passing tests and echo normally for test fail or error.
-c (--catch): First Control-C waits current running test and reports after its completion. A second Control-C raises the normal KeyboardInterrupt exception.
--locals: show local variables in trackbacks.

-s and -p:  are discovery mode parameters.

Accepted input file list: 

The unittest module can be run from the following different manner from a command-line environment.

Class or Module: 

python -m unittest test_module1 test_module2python -m unittest test_module.TestClasspython -m unittest test_module.TestClass.test_method

File with path: 

python -m unittest tests/test_something.py

Test Discovery: 

python -m unittest
Here no input arguments are provided. This lead unittest module into a discovery mode, in which unittest searches test case class by itself in the given or current directory (by default).

Test Discovery

Running requirements: 

All of the test files must be modules or packages (including namespaces packages) importable from the top-level directory of the project!!! (this can be denoted by -t option)

Arguments options: 

-s (--start-directory): Directory to start discovery (. default)
-p (--pattern): Pattern to match test files (test*.py default)
-t (--top-level-directory): Top level directory of project (default to start directory)

Prepare the basic test unit: a Test Case

Subclass of TestCase

import unittest 
class DefaultWidgetSizeTestCase(unittest.TestCase):    def test_default_widget_size(self):        widget = Widget('The widget')        self.assertEqual(widget.size(), (50, 50))
Test (test_default_widget_size) is labelled as failure if function assertEqual() raised an exception. Any other exceptions are labelled as errors. 

import unittest 
class WidgetTestCase(unittest.TestCase):    def setUp(self):        self.widget = Widget('The widget')    def tearDown(self):        self.widget.dispose()
setUp() and  tearDown() are used to prepare and cleanup tests. They will be called for every single test. 

If setUp() fails, the test case is labelled as failed. 
If setUp() succeeded, tearDown() will be run whether the test function is succeeded or not.

To use the test suite: 
def suite():    suite = unittest.TestSuite()    suite.addTest(WidgetTestCase('test_default_widget_size'))    suite.addTest(WidgetTestCase('test_widget_resize'))    return suite 
if __name__ == '__main__':    runner = unittest.TextTestRunner()    runner.run(suite())

FunctionTestCase

This is a method to reuse the old test code back from the dark ages without systematic testing components. This is where FuntionTestCase comes into consideration.

FunctionTestCase is a subclass of the TestCase, which wraps an existing test function. Its flexibility makes the setUp() and tearDown() functions available to be provided:

def testSomething():
    something = makeSomething()
    assert something.name is not None
    # ...

testcase = unittest.FunctionTestCase(testSomething,
                                     setUp=makeSomethingDB,
                                     tearDown=deleteSomethingDB)

Even though the FunctionTestCase provides an alternative method to construct a test case. But this is not a recommend solution.

Skip a test

The following decorators implement test skipping and expected failures:
@unittest.skip(reason)
Unconditionally skip the decorated test. reason should describe why the test is being skipped.
@unittest.skipIf(condition, reason)
Skip the decorated test if condition is true.
@unittest.skipUnless(condition, reason)
Skip the decorated test unless condition is true.
@unittest.expectedFailure
Mark the test as an expected failure. If the test fails when run, the test is not counted as a failure.
exception unittest.SkipTest(reason)
This exception is raised to skip a test.
setUp() and tearDown() will not be run for skipped tests. setUpClass() and tearDownClass() will not be called for skipped test classes.

Subtest

This is specifically for iteration tests, where the test is commonly terminated after the first failure, which provide no obvious reason. The definition of the subtest would keep the iterative tests running to the end to show the abnormality along the whole iterative process. 

Here is pretty much the most background of using Python unittest module. Most of the above content is from the Python Manual. Please refer it for more details. 

Tuesday, 10 October 2017

CMake Learning 1

Here is a snippet collect of learning CMake tool, which replaces my autoconf tool sets.

This is not a complete and clean version. A final cleanse and restructure are required,


Basic Usage:
  1. CMake is case insensitive. 
  2. Variables: 
    1. Variable: ${VAR}. set is used to set variable values: set (Foo a b c).
    2. command(${Foo}) = command(a b c). command("${Foo}") = command("a b c").
    3. $ENV{VAR}: is for accessing to system environment variables.
  3. CMakefile:
    1. # means a start of a comment line in the file.
    2. add_executable: build executable using the given list of files.
    3. find_library: look for specific libraries with different NAMES and in different PATHS. 
    4. target_link_library: link libraries to executables.
  4. Run CMake: 
    1. Two directories: Source directory and Build directory
    2.  In-source build: source directory and build directory are the same.

Main Structures:
The main components in CMake are implemented as C++ classes, which are then referenced in many of CMake commands.

The following is the structure of the main CMake components:


  1. Source files: C or C++ source code.
  2. Targets: is typically an executable or library.
  3. Directory: each directory contains one or several targets which are built from the source files in the directory.
  4. Generators: each directory has a local generator that is responsible for generating the Makefiles or project files for the directory. All local generators share a common global generators to oversee the build process.
For example, under Visual Studio 7, the global generator creates a solution file for the entire project while the local generators create a project file for each target in their directory.
In Unix makefile generator, the local generators create the makefiles in each sub-directory and the global generator creates the top-level makefile in the root directory.

Mechanism of CMake commands:
  • There are two main parts for each command: InitialPass method and FinalPass method. 
  • InitialPass method accepts arguments and local generator (cmMakefile instance). Apply the command using the arguments and store the results in the provided cmMakefile instance.
  • FinalPass method runs only after the invocation of InitialPass methods from all commands. Not all commands have FinalPass. For some commands, the global information is required, which may not be available in the InitialPass phase.

Targets:
  • add_library, add_executable and add_custom_target command creates a target. eg: add_library (foo STATIC foo1.c foo2.c) [created a static library called foo]
    • STATIC, SHARED, MODULE are available options. In most system, SHARED and MODULE are the same but not in Mac OS X. 
    • If it is blank, the variable BUILD_SHARED_LIBS controls whether a shared or static library should be built. By default, CMake builds a static library.
  • set_target_property and get_target_property commands to manipulate target's properties.
  • target_link_libraries command to denote a list of libraries that the target link against. Accepted format: libraries, full path to libraries or name of a library from an add_library command.

Source Files:

  • set_source_files_properties and get_source_file_property are to access a source file's properties.
    • COMPLILE_FLAGS
    • GENERATED
    • OBJECT_DEPENDS
    • ABSTRACTWRAP_EXCLUDE
Variables:

  • Variables have scope which is after its definition.
  • Two examples of scope:
    function (foo)
        message(${test} # output 1 here
        set (test 2)
        messgae(${test} # output 2 here 
    endfunction()

    set(test 1)
    foo()
    message (${test}) # This is still a 1.

vs

    function (foo)
        message(${test} # output 1 here
        set (test 2 PATENT_SCOPE)
        messgae(${test} # output 2 here 
    endfunction()

    set(test 1)
    foo()
    message (${test}) # This is 2 now.


  • if command:
    set (FOO 1)
 
    if (${FOO} LESS 2)
        set (FOO 2)
    else (${FOO} LESS 2)
        set (FOO 3)
    endif(${FOO} LESS 2
  • loop command:

    set (items_to_buy apple, orange pear beer)

    foreeach (item ${iterm_to_buy})
        message("Don't forget to buy one ${itme}")
    endforeeach ()

Cache Entries:

  • In case the user is allowed to build the project to set a variable from the CMake user interface, the variable must be a cache entry.
  • A cache file is produced in the build directory, which stores the user's selections and choices as its main purpose.
  • option (USE_JPEG "Do you want to use the jpeg library"). This command creates a variable called USE_JPEG and put it into the cache.
  • Ways of create a cache entry: 
    • option
    • find_file
    • set using CACHE option: set (USE_JPEG ON CACHE BOOL "include jpeg support?"), the following variable types must be used for GUI to control how that variable is set and displayed.
      • BOOL
      • PATH
      • FILEPATH
      • STRING
  • Another purpose of using cache is to store key variables that are expensive to determine, such as CMAKE_WORDS_BIGENDIAN, which needs to compile and run a program to determine its value. This is to prevent having to recompute them every time CMake is run.
  • mark_as_advanced is used to set a cache entry as an advanced cache, which will not be shown at first when the CMake GUI is run. The advanced cache entries are other options that the user can modify, but typically will not.
  • the value of cache entry can be restriced to a limited set of predefined options (pull down list) by setting it's property: 
    • set (CRYPTOBACKEND "OpenSSL" CACHE STRING "Select a cryptography backend")
    • set_property (CACHE CRYPTOBACKEND PROPERTY STRINGS "OpenSSL" "LibTomCrypt" "LibDES")
  • The following points are worth to pointing: 
    • Variables in cache can still be overridden in a CMakeLists file using set without CACHE optoin.
    • Cache values are checked only if the variable is not found in the current cmMakefile instance before CMakeLists file processing begins.
    • The set command will set the variable for processing the current CMakeLists file without changing the value in the cache.
    • "Once a variable is in the cache, its "cache" value cannot normally be modified from a CMakeLists file. The reasoning behind this is that once CMake has put the variable into the cache with its initial value, the user may then modify that value from the GUI. If the next invocation of CMake overwrote their change back to the set value, the user would never be able to make a change that CMake wouldn't overwrite. So a set (FOO ON CACHE BOOL "doc") comman will typically only do something when the cache doesn't have the variable in it. Once the variable is in the cache, that command will have no effect."
Build Configurations:

  • Supported build configurations: 
    • Debug, has basic debug flags turned on.
    • Release, has basic optimizations turned on.
    • MinSizeRel, has the flags that produce the smallest object code, but not necessarily the fastest code.
    • RelWithDebInfo, builds an optimised build with debug information as well.
  • For Visual Studio IDE, CMAKE_CONFIGURATION_TYPES is used to tell CMake which configurations to put in the workspace.
  • For Makefile, only one configuration can be active , whcih is specified by the CMAKE_BUILD_TYPE variable. The corresponding flags (CMAKE_CXX_FLAGS_<ConfigName>) are added to the compile lines. Make file doesn't create subdirectories for object files. So to build both debug and release trees, two separated build directories are required and use the out of source build feature of CMake, for example: (ccmake ../MyProject -DCMAKE_BUILD_TYPE:STRING=Debug) or (ccmake ../MyProject -DCMAKE_BUILD_TYPE:STRING=Release)




Thursday, 1 August 2013

Endnote X7 export to Bibtex

I converted the endnote library to bibtex several years ago. It's totally behind my mind already. Today I want to try the endnote X7 and to see whether something improved in this new version endnote. It is rather good to involve the bibtex template into its export style options. However, I found that there is no citation key for each reference at all. According to the search, the endnote needs the label of a reference as its citation key. But it seems that it doesn't work quite smoothly.  Therefore, I downloaded a Bibtex Export from endnote's style manager on its site and restart the whole endnote. I am not quite sure if the restart works or the new export style works. Finally, I got it work with reference label to be its citation key.

Wednesday, 5 June 2013

Backup a table in MySQL

In my experiment, each experiment running needs a table in the control machine to record the global inserted files in the system. When an experiment finished, a new empty table should be created in order to record the new experiment's inserted files. For later experiment process, the old table should be backed up also. There could be more efficient and reliable way to back up the tables in a MySQL database, but here is my method to accomplish this task with two SQL commands:
  1. Rename the old table: RENAME TABLE store_record TO <new_name>
  2. Create an empty table: CREATE TABLE <new_name> LIKE store_record
 After these two SQL command, the original 'store_record' table becomes 'new_name' table and an empty new 'store_record' table is created.
WARNING: there is no quotation marks for table name!

This is put in the process of cleaning up experiment results. If cleaning up is necessary, then the data in 'store_record' table is useless. And it is free to be replaced by an empty one for next experiment. If the cleaning up is not performed, it means that the data in last experiment is useful in the next experiment, then the remaining of data in 'store_record' is meaningful.

Sunday, 2 June 2013

libssh remove directory using sftp

In libssh, trying to remove an non-empty directory on a remote host will get a SSH_FX_FAILURE error.

Friday, 24 May 2013

SFSlite output stream system and Chord logging

In Chord source code, there are a great number of "warn", "warnx", "warnt", "fatal" and "panic". They are the output stream part of sfslite library and are used to replace the error output mechanics in standard C++ library in a asynchronous way. According to the tutorial of libasync from David and Frank, et al., these stream makes efforts to accumulate and write data to the terminal in chunks with reasonable boundaries.

This mechanic is defined in err.h and err.C in sfslite/async/ directory. There are some derivations for "warn":
    warn:
      - vwarn: invoke the underlying vfmt of strbuf.
      - warnx: the program name and pid are shown in each message.
      - warnt: a time stamp is shown in each message.
      - vwarnx: invoke the underlying vfmt of strbuf with program name
                      and pid shown

    fatal: message start with "fatal", exit program after messaging
    panic: message start with "PANIC", exit and dump core after messaging.

    assert: this is an replacement of C assert using the panic.

Here is what I found from the sfslite source code.

Actually, there is a quite similar mechanic in Chord called modlogger in chord/utils/modlogger.*, which is labelled an employed idea from sfslite. The modlogger is actually a small logging system with logging levels (CRIT, WARNING, INFO, TRACE) and logging target (standard output or a file descriptor).

Saturday, 23 March 2013

C/C++ Programming Tips

Here, some useful tips or unknowns of C/C++ programming are listed for further reference:

1. Stand alone curly brackets in code.
Sometimes a pair of curly brackets can be found in a C/C++ code file. It seems to be useless:

Configurator::only ().dump();

{
    strbuf x = strbuf ("starting: ");
    for (int i = 0; i < argc; i++) {
        x << argv[i] << " ";
    }
    x << "\n";
    info << x;
}

Here, the curly brackets is not necessarily to exist. However, they have their meanings from two different point of views: Scope perspective and Legacy perspective.
In scope perspective, the codes in the pair of curly brackets is in a new sub scope.
In legacy perspective, the legacy C standard needs variable declarations to be in the very front of the code. The curly brackets are able to make a new "beginning".
I am working on a C++ project. So the original coder considered in a scope perspective.