Wednesday, 22 October 2014

[Coverage] some terms and definitions

Terms

Terms

  • condition:
    • a condition is a leaf-level Boolean expression (it cannot be broken down into a simpler Boolean expression).
    • condition: 2 > 1, a == b
    • not condition: (2 > 1) || (a == b)
  • decision:
    • a Boolean expression composed of conditions and zero or more Boolean operators. a decision without a Boolean operator is a condition
    • condition is a decision
    • decision: (2 > 1) || (a == b)

Coverage

  • statement coverage:
    • each statement is executed at least once
  • function coverage:
    • each function is called at least once
  • branch coverage:
    • each branch of control structure is executed at least once
  • condition coverage:
    • every condition in a decision in the program has taken all possible outcomes at least once.
  • decision coverage
    • Every point of entry and exit in the program has been invoked at least once, and every decision in the program has taken all possible outcomes at least once
  • condition/decision coverage:
    • every point of entry and exit in the program has been invoked at least once, every condition in a decision in the program has taken all possible outcomes at least once, and every decision in the program has taken all possible outcomes at least once.
  • modified condition/decision coverage:
    • every point of entry and exit in the program has been invoked at least once, every condition in a decision in the program has taken on all possible outcomes at least once, and each condition has been shown to affect that decision outcome independently. A condition is shown to affect a decision's outcome independently by varying just that condition while holding fixed all other possible conditions. The condition/decision criterion does not guarantee the coverage of all conditions in the module because in many test cases, some conditions of a decision are masked by the other conditions. Using the modified condition/decision criterion, each condition must be shown to be able to act on the decision outcome by itself, everything else being held fixed. The MC/DC criterion is thus much stronger than the condition/decision coverage.
    • Independence of a condition is shown by proving that only one condition changes at a time.
Examples
  • if (a && b) {}
    • [(a=true, b=false), (a=false, b=true)] to satisfy condition coverage, but not for branch coverage and decision coverage, since a && b are both true
    • [(a=true, b=false), (a=false, b=false)] to satisfy branch coverage and decision coverage, but not for condition coverage since b=true is not covered
    • [(a=true, b=false), (a=false, b=true), (a=false, b=false) ] to satisfy condition/decision coverage but not mc/dc because each condition (a or b) is evaluated to true once and false once but do not have an effect on the outcome.
      • (a=true, b=false), (a=false, b=false) -- this is not a effective test case in mcdc since the outcome of both is the same: false, and the true and false of a don't have effect on final outcome
      • (a=true, b=true), (a=false, b=true) -- it is effective test case in mcdc since the true and false of a do have effect on final outcome: true or false
    • [(a=true, b=true), (a=false, b=true), (a=true, b=false) ]
      • condition/decision coverage
      • mcdc
        • (a=true, b=true), (a=false, b=true)
        • (a=true, b=true), (a=true, b=false)

branch vs. decision coverage:

As ISTQB Foundation book gives, branch coverage is closely related to decision coverage and at 100% coverage they give exactly the same results. Decision coverage measures the coverage of conditional branches; branch coverage measures the coverage of both conditional and unconditional branches. The Syllabus uses decision coverage, as it is the source of the branches. Some coverage measurement tools may talk about branch coverage when they actually mean decision coverage. (c) ISTQB foundation book. [From http://stackoverflow.com/questions/12398494/is-branch-coverage-the-same-as-decision-coverage]

References

Saturday, 9 August 2014

[Vim] open VOom outliner automatically for specific file type

VOom (Vim Outliner of Markups) is a very useful outline plugin for Vim. It can support many markup modes, such as popular markdown, latex, pandoc, html and python. For me,
  • markdown - used to write notes, and it can be easily converted into html or pdf by markdown2.py, pandoc or Mou, then paste html to blog
  • latex - used to write research paper

Typical Usage of VOom

  • Use Vim to open Latex file
  • Type :Voom latex to open VOom outline window in left panel
  • Use the section tree in VOom for jumping to desired section of paper

The Problems

However sometimes I have to open up to ten Latex files for editing at the same time, I need typing :Voom latex for ten times. It's not productive and boring.

Solution

Vim has an autocmd feature to open a command automatically depending on the events. More detials see vimdoc (:help autocmd).
  • Add the following lines in .vimrc

    " after read in tex file and then execute Voom latex 
    autocmd BufRead *.tex :Voom latex 
    autocmd BufRead *.mkd :Voom markdown
    
  • It will execute :Voom latex when opening a Latex file and :Voom markdown for mkd file

Wednesday, 6 August 2014

[OS] VxWorks Task Scheduling

VxWorks

 
Ready/Exec
the task that is ready to run and not waiting for any resource other than CPU.
Pended
the task that is blocked and waiting for availability of resources. For example, semTake() will block the task if the semaphore is not available, and semGive() will take it back to Ready state.
Delayed
the task that is waiting for an amount of time to pass. For example, taskDelay() will take the task to this state. After the timeout is expired, it becomes Ready state.
Pended & Delayed
the task that is blocked and waiting for availability of resources with a timeout.
Suspended
the task that is unavailable to execution. It’s primarily used for debugging. It will not affect task state, but only task execution. For example, taskSuspend() of a task in Ready will lead to this state, and taskResume() will resume this task to Ready.
Delayed & Suspended
the task that is both delayed and suspended. If the task is resumed, its state will be delayed. For example, taskSuspend() of a task in Delayed will lead to this state, and taskResume() will resume this task to Delayed.
Pended & Suspended
the task that is both pended and suspended. If the task is resumed, its state will be pended. For example, taskSuspend() of a task in Pended will lead to this state, and taskResume() will resume this task to Pended.
Pended & Delayed & Suspended
the task that is pended, delayed and suspended. If the task is resumed, its state will be pended & delayed. For example, taskSuspend() of a task in Pended and Delayed will lead to this state, and taskResume() will resume this task to Pended and Delayed.

Tuesday, 5 August 2014

[OS] Operation System Process Scheduling

General

CPU and I/O Bursts

CPU Burst
the amount of time the process uses the processor before it is no longer ready (for example I/O request)
I/O Burst
CPU-I/O Burst Cycle
process execution consists of a cycle of CPU execution and I/0 wait. Processes alternate between these two states. Process execution begins with a CPU burst. That is followed by an I/O burst, which is followed by another CPU burst, then another I/0 burst, and so on. Eventually, the final CPU burst ends with a system request to terminate execution. ([Operation System Concept])
I/O-bound program
has many short CPU bursts.
CPU-bound program
has a few long CPU bursts.

Scheduler

Long-term Scheduler
or job scheduler, selects processes from the pool and loads them into memory for execution. The long-term scheduler controls the degree of multiprogramming (the number of processes in memory) and is performed when new process is created
Medium-term Scheduler
controls processes to be swapped out of memory and be swapped in later, namely swapping. The decision to add to the number of processes that are partially or fully in main memory.
Short-term Scheduler
or CPU scheduler, selects from among the processes that are ready to execute and allocates the CPU to one of them. It controls which ready process to be executed in CPU next.

Dispatcher

The dispatcher is the module that gives control of the CPU to the process selected by the short-term scheduler. It involves
  • switching context
    • context switching is expensive
    • context is a snapshot of the values of the general-purpose, memory management, and other special registers.
  • switching to user mode
  • jumping to the proper location in the user program to restart that program
Dispatch Latency
- time it takes for the dispatcher to stop one process and start another running.

Scheduling Diagram


Linux Kernel

General States


 
Ready
the process is competing for the processor or could be executed, but another process is currently being executed.
Running
the process is active and running
Suspend
the process is blocked and sleeping
Stopped
the process is suspended by a signal or a debugger
Zombie
the process has finished executed, but it is still references in the system. The process is exiting but has not yet been waited for by its parent

Process States defined in sched.h of Linux 2.6.31


Process states:
TASK_RUNNING
the process is either executing on a CPU or waiting to be executed.
TASK_INTERRUPTIBLE
the process is suspended (sleeping) or blocked, and waiting for a signal or explicit wakeup (such as wakeup_process()). Raising a hardware interrupt, releasing a system resource the process is waiting for, or delivering a signal are examples of conditions that might wake up the process (put its state back to TASK_RUNNING).
TASK_UNINTERRUPTIBLE
like TASK_INTERRUPTIBLE, but a signal won’t wake it up. It is valuable, however, under certain specific conditions in which a process must wait until a given event occurs without being interrupted. For instance, this state may be used when a process opens a device file and the corresponding device driver starts probing for a corresponding hardware device. The device driver must not be interrupted until the probing is complete, or the hardware device could be left in an unpredictable state.
TASK_STOPPED
process execution has been stopped; the process enters this state after receiving a SIGSTOP, SIGTSTP, SIGTTIN, or SIGTTOU signal.
TASK_TRACED
process execution has been stopped by a debugger. For example, each signal during ptrace system call with PTRACE_ request may put process in this state, and it will be put back to TASK_RUNNING state only after debug process executes ptrace system call with PTRACE_CONT or PTRACE_DETACH request.
TASK_DEAD
the process is being cleaned up and the task is being deleted. It’s the state of process in exiting. Finally the exit state will be one of EXIT_ZOMBIE or EXIT_DEAD.
Process exit states:
EXIT_ZOMBIE
process execution is terminated, but the parent process has not yet issued a wait4() or waitpid() system call to return information about the dead process. Before the wait()-like call is issued, the kernel cannot discard the data contained in the dead process descriptor because the parent might need it.
EXIT_DEAD
the final state: the process is being removed by the system because the parent process has just issued a wait4() or waitpid() system call for it.

References

Operation System Concept, 8th Edition
Understanding Linux Kernel, 3rd Edition
Linux 2.6.31 Kernel Source Code

Thursday, 19 June 2014

[Ada] Tagged record type and Class-wide operation dispatching

This example shows how to use tagged record type and class-wide operation dispatching to achieve run-time polymorphism.

Class Hierarchy

One root class Shape, and three subclasses Point, Circle and Rectangle. Each class has coordinator (x and y) and area function. Besides, Circle has additional radius and Rectangle has extended width and length.

Source Code

Shape

  • shapes.ads
  • package shapes is
        type Shape is tagged private;
    
        function Area (S : in Shape) return Float;
    
    private
        type Shape is tagged record
                X : Float ;
                Y : Float ;
        end record;
    end shapes;
    
  • shapes.adb
  • package body shapes is
    
        function Area (S : in Shape) return Float is
        begin
            return 0.0;
        end Area;
    end shapes;
    

Point

  • points.ads
  • with shapes; use shapes;
    
    package points is
        type Point is new Shape with private;
    
        function Area (P : in Point) return Float;
    end points;
    
  • points.adb
  • package body points is
    
        function Area (P : in Point) return Float is
        begin
            return 0.0;
        end Area;
    end points;
    

Circle

  • circles.ads
  • with shapes; use shapes;
    
    package circles is
        type Circle is new Shape with private;
    
        function Area (C : in Circle) return Float;
    private
        type Circle is new Shape with record 
                Radius : Float ;
        end record;
    end circles;
    
  • circles.adb
  • package body circles is
    
        function Area (C : in Circle) return Float is
            pi : CONSTANT Float := 3.1415926;
        begin
            return 2.0 * pi * (C.Radius * C.Radius);
        end Area;
    
    end circles;
    

Rectangle

  • rectangles.ads
  • with shapes; use shapes;
    
    package rectangles is
        type Rectangle is new Shape with private;
    
        function Area (R : in Rectangle) return Float;
    private
        type Rectangle is new Shape with record 
                Length : Float ;
                Width : Float ;
        end record;
    end rectangles;
    
  • rectangles.adb
  • package body rectangles is
    
        function Area (R : in Rectangle) return Float is
        begin
            return R.Length * R.Width;
        end Area;
    
    end rectangles;
    

Test

  • test.adb
  • With shapes; use shapes;
    With points; use points;
    With circles; use circles;
    With rectangles; use rectangles;
    
    procedure test is
        p : Point;
        c : Circle;
        r : Rectangle;
    
        area_of_shape : Float := 0.0;
    
        function getArea (S: Shape'Class) return Float is
            temp : Float;
        begin
            temp := Area(S);
            return temp;
        end problem;
    
    begin
        area_of_shape := getArea(p);
        area_of_shape := getArea(c);
        area_of_shape := getArea(r);
    end test;
    

Tuesday, 10 June 2014

[Perl] signal handler

1. Use %SIG hash to trap control signal

You can set the values of the %SIG hash to be the functions you want to
handle the signal. After perl catches the signal, it looks in %SIG for a
key with the same name as the signal, then calls the subroutine value for
that key. The following is signal handler for INT signal [From perldoc -q SIG]

# as an anonymous subroutine
$SIG{INT} = sub { syswrite(STDERR, "ouch\n", 5 ) };

# or a reference to a function
$SIG{INT} = \&ouch;

# or the name of the function as a string
$SIG{INT} = "ouch";

sub ouch {
    die "Caught a signal: $!";
}

We can define handlers for other signals as well.

$SIG{TERM} = sub { print STDERR, "Going to terminate."; };
$SIG{__DIE__} = sub { die "Going to die:".shift; };
$SIG{__WARN__} = sub { die "Going to die:".shift; };

The key of %SIG hash can be INT, ‘INT’, and __INT__.
signal handler also can be defined with eval, such as

eval {
       local $SIG{ALRM} = sub { die "timeout\n" };
};

[Linux] system(3)

system(3) is a C library function and also can be used in perl.

SYNOPSIS in Perl

system LIST
system PROGRAM LIST

Description

  • system will do a fork first and then the parent will wait fro the child process, where the command is running on, to exit.
  • The return code from the command is got by wait(&ret) in parent process. An example of fork can be found by $man 2 wait.

    /**
     * wait(2)
     */
    #include <sys/wait.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <stdio.h>
    
    int main(int argc, char *argv[])
    {
        pid_t cpid, w;
        int status;
    
        cpid = fork();
        if (cpid == -1) { perror("fork"); exit(EXIT_FAILURE); }
    
        if (cpid == 0) {
            /* Code executed by child */
            printf("Child PID is %ld\n", (long) getpid());
            if (argc == 1)
                pause();                    /* Wait for signals */
            _exit(atoi(argv[1]));           /* exit code from child process */
        } else {
            /* Code executed by parent */
            do {    
                /* get exit code of child process in status */
                w = waitpid(cpid, &status, WUNTRACED | WCONTINUED); 
                if (w == -1) { perror("waitpid"); exit(EXIT_FAILURE); }
    
                if (WIFEXITED(status)) {
                    printf("exited, status=%d\n", WEXITSTATUS(status));
                } else if (WIFSIGNALED(status)) {
                    printf("killed by signal %d\n", WTERMSIG(status));
                } else if (WIFSTOPPED(status)) {
                    printf("stopped by signal %d\n", WSTOPSIG(status));
                } else if (WIFCONTINUED(status)) {
                    printf("continued\n");
                }
            } while (!WIFEXITED(status) && !WIFSIGNALED(status));
            exit(EXIT_SUCCESS);
        }
    }
        

  • The return code of system is exactly the same as status in above example. It's a 16-bit value with high 8-bit for exit code and low 8-bit for signal id. WEXITSTATUS just extracts exit code from status and like status >> 8.

  • use $man 3 system to get its reference in C and $perldoc -f system to get in perl.

  • See this link for more information

    http://perldoc.perl.org/functions/system.html

[Perl] system command timeout implementation

An example

This example is from perldoc

  • Reference: $perldoc -f alarm
# eval returns the value of last expression evaluated
# if no timeout, return value will be 'alarm 0;', which return 0
# otherwise, the last statement executed is 'sub { die "alarm\n" };'
# since die within eval will stuff error message into $@, the $@ will contain "alarm"

eval {
    local $SIG{ALRM} = sub { die "alarm\n" }; # NB: \n required
    # after $timeout seconds, it will issue SIGALRM signal to 
    # this process unless it is cancelled by a new alarm (like 
    # 'alarm 0;' below)
    alarm $timeout;
    $nread = sysread SOCKET, $buffer, $size;
    alarm 0;
};

# if $@ is 0, no timeout happen, otherwise, $@ contains error message "alarm"
if ($@) {
    # propagate unexpected errors (if it is not timeout, die)
    die unless $@ eq "alarm\n";   
    # timed out
}
else {
    # didn’t
}

[IDE] Source Code Syntax Highlight in Blogger

How to enable the source code syntax hightlighter for google blogger

SyntaxHighlighter

  • Go to Blogger's template
  • Click "Backup/Restore" in the upright of page to backup current template at first
  • Then "Edit Template"
  • Add the following lines just before the </head> line
        
        
        

Examples

js


<pre class="brush: js"> int function(int i) { return i; } </pre> <br />

int function(int i)
{
    return i;
}

C/C++


<pre class="brush: c"> int function(int i) { return i; } </pre> <br />

int function(int i)
{
    return i;
}

Thursday, 29 May 2014

Model Checking Evolution

Explicit-State Model Checking (EMC)

  • State space can be viewed as graph
  • Exhaustively enumerates all states of the system and traverses each edge of the graph
  • Problem
    • Huge state space and difficult to enumerate all (computer capability CPU and memory consumption)
  • Depth-First Search or Breadth-First Search
    • BFS: the shortest counterexample available
    • BFS: more memory required since it needs to store back-pointers to predecessor state
  • States: 10^5

Symbolic Model Checking

  • Manipulate set of states and transitions, rather than individual state and transition
  • Set of states and transitions is represented Boolean formula (boolean encoding)
  • BDD: boolean formula as Binary Decision Diagram

Boolean function:

  • describes how to determine a Boolean value output based on some logical calculation from Boolean inputs
  • for a set A, each element of f(A) is called a Boolean function generated by A.
  • each boolean function is a unique representation
  • for example, for two binary variables (x and y), it has (2^2^(card(A)) = 16) boolean function. Here f1 = x AND y, and f2 = x OR y
    x | y | f1 | f2 | …
    0 | 0 | 0 | 0 | …
    0 | 1 | 0 | 1 | …
    1 | 0 | 0 | 1 | …
    1 | 1 | 1 | 1 | …
  • Each element in the set of states is encoded as bit-string
    • for a variable vector V={v1,v2,…vn}. A bit-string can represent 2^n states. For example, if n = 3, the set of states can be {000, 001, 010, 011, 100, 101, 110, 11}. Here bit-string 000 is a representation of bits vector {v1=0,v2=0,v3=0}.
  • Characteristic boolean function
    • represents a subset of states which makes the function is true.
    • for instance, if characteristic function is v1 AND v2, it means v1 and v2 should be both true. So the set will be {110,111}.
  • Current state of a vector of variable is symbolised as a bit-string
  • Transition is a state pair (s,s’), a combined bit-string
  • States: 10^100
  • SMV: Symbolic Model Verifier

Bounded Model Checking

  • Bounded in user-supplied time k
  • For transition system M, temporal logic formula f, construct a propositional formula Omega(k) that is satisfiable if f is valid along the path of length k
  • Path of length k is expressed as: I(s0) AND R(s0,s1) AND R(s1,s2) … AND R(sk-1, sk)
  • For example, if k = 2, and f = EF p, then Omega(2)=I(s0) AND R(s0,s1) AND R(s1,s2) AND (p0 OR p1 OR p2), which means from initial states, after up to 2 steps (transition), at least one p is true (exactly the same meaning as EF - exists a path finally p holds)
    • not Omega(2) = I(s0) AND R(s0,s1) AND R(s1,s2) AND (not p0 AND not p1 AND not p2) - counterexample, all p does not hold.
  • For example, if k = 2, and f = AG p, then Omega(2)=I(s0) AND R(s0,s1) AND R(s1,s2) AND (p0 AND p1 AND p2), which means from initial states, after up to 2 steps (transition), each p is true (exactly the same meaning as AG - for all paths p always holds)
    • not Omega(2) = I(s0) AND R(s0,s1) AND R(s1,s2) AND (not p0 OR not p1 OR not p2) - counterexample, at least one p does not hold.
    • Safety-checking becomes not Omega(k) is not satisfiable. If it is satisfied, a satisfying assignment is given and that is the counterexample.
  • Using SAT
  • States: 10^1000

SAT

  • given a propositional formula, find if there exists an assignment to Boolean variables that make the formula true.
    • for example, two boolean variables x and y. Formula p = not x AND not y. To make p true, A={x=0,y=0} is the only SATisfying assignment.

Pros

  • SAT solvers do not require exponential space and large designs can be checked very fast. BDDs based model checking uses DFS or BFS which does require a large memory.

References

Friday, 2 May 2014

[English Writing] Good references

Reference

In particular, his calculations suggest, the firn of the Wilkins, Larsen C, George VI and Cosgrove shelves in west Antarctica will be saturated with meltwater by the end of the century--a finding which echoes that of a study led by Jan van Angelen, also of Utrecht University, that was published last year in Geophysical Research Letters. [P67, The Economist (Feb 07, 2014)]

This, as they reported in December’s Nature Geoscience, contains some 140 bil- lion tonnes of liquid water. [P67, The Economist (Feb 07, 2014)]

Further explanation or description

Parenthesis

There is, for example, little Neanderthal DNA on the X chromosome (which, along with the Y chromosome, determines an individual’s sex). [P66, The Economist (Feb 07, 2014)]

Dr Forster and his colleagues think the aquifer they have found covers an area of 70,000 square kilometres (about the size of Ireland). [P67, The Economist (Feb 07, 2014)]

em dash (--)

For instance, genes affecting the production of keratin--an important component of hair and skin--showed more Neanderthal influence than most. [P66, The Economist (Feb 07, 2014)]

This would not matter as a one-off, but if it happened repeatedly as new firn formed the consequences could be serious--particularly if, in escaping, it caused more hydrofracturing or acted as a lubricant that encouraged previously stable ice to slip from its bed- rock into the sea. [P67, The Economist (Feb 07, 2014)]

How likely that sort of thing is to happen--and thus how much of a threat firn really is--has yet to be determined. [P67, The Economist (Feb 07, 2014)]

Enumerate

And two studies, one just published in Nature, and one in Science, have now looked in detail at this miscegenation, and tried to understand its consequences. [P66, The Economist (Feb 07, 2014)]

Emphasise

But the fact that so little is known about it emphasises a wider point. [P67, The Economist (Feb 07, 2014)]

Misc

Crucially, though the amount of Neanderthal DNA in any individual is small, the exact bits vary a lot from person to person. [P67, The Economist (Feb 07, 2014)]

Technically, Neanderthals may be gone. But their DNA ghosts linger on. [P67, The Economist (Feb 07, 2014)]

SVN "local unversioned, incoming add upon update"

Problem
$ svn st -q
D     C dir
      >   local unversioned, incoming add upon update
D       dir/file
 
Solution
$ svn resolve --accept working dir
Resolved conflicted state of 'dir'
$ svn revert dir
Reverted 'dir'
$ svn status
D       dir/file
$ svn revert dir/file
Reverted 'dir/file'
$ svn st -q 
Reference
  • http://tomhennigan.blogspot.co.uk/2012/01/resolve-tree-conflict-svn-local.html 

Thursday, 6 February 2014

[Makefile] filter unnecessary string and extract id number from a list of strings

For example, here’s a list of strings tst2b tst2222 tst22b 222b test tst22b2 tst222_ tst2333 tsta223. I want to only keep the string tst2222 tst2333 which starts with tst and follows with number, and no other string allowed. Besides, I will extract the id 2222 and 2333, and finally make them a comma separate list 2222,2333.
TEST_NAMES := tst2b tst2222 tst22b 222b test tst22b2 tst222_ tst2333 tsta223

# get the test id but excluded the case which doesn't have prefixed 'tst'
TST_IDS := $(foreach test,$(filter tst%,$(TEST_NAMES)), $(subst tst,,$(test)))

comma := ,
empty :=
space := $(empty) # 
# Comma separate test id lists, such as 123,2256,2256b
TST_IDS_COMMA_T := $(subst $(space),$(comma),$(strip $(TST_IDS)))

# Only keep the numbers and exclude the test which has the word [a-zA-Z_] in its id.
TST_IDS_COMMA := $(shell echo $(TST_IDS_COMMA_T) | sed 's/[^,]*[a-zA-Z_][^,]*//g; s/,,*,/,/g; s/^,//g; s/,$$//g')
  • filter function will only keep the string which begins with tst
  • subst will replace tst with empty, which removes the tst
  • foreach will recursively loop each test after filter
  • Second subst replace space ` with comma,`
  • The $TST_IDS_COMMA_T is like 2222,22b2,2333. sed will substitute the string which has alphabet [a-zA-z] and underline _ with empty, then replace multiple comma such as ,,, with one comma ,. The leading comma , and comma in the end of line are also removed.

[Java] Visitor Design Pattern in Java

Visitor Design Pattern

In object-oriented programming and software engineering, the visitor design pattern is a way of separating an algorithm from an object structure on which it operates. A practical result of this separation is the ability to add new operations to existing object structures without modifying those structures. It is one way to easily follow the open/closed principle. (from Wikipedia)
  • Open/Closed Principle
In object-oriented programming, the open/closed principle states “software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification“;[1] that is, such an entity can allow its behaviour to be modified without altering its source code. This is especially valuable in a production environment, where changes to source code may necessitate code reviews, unit tests, and other such procedures to qualify it for use in a product: code obeying the principle doesn’t change when it is extended, and therefore needs no such effort. (from Wikipedia)

When to use the visitor pattern

  1. Current class and object structure is fixed, and can’t make changes to it. But you do need to add new operations to that hierarchy. The dilemma is that you want to add operations to the base class, but you can not modify the base class
  2. Some unrelated operations need to be added on objects in an object structure, but you don’t want to add each operation in each object to let the class messed, and hope a good structure of class
  3. Object structure is seldom changed, but the operations may be added or modified frequently. Similar to 1
  4. Classes in object structure have difference interfaces and you expect that which operation is performed depends on its concrete class.

How to use visitor pattern (Take AST as an instance)

  • All nodes have the similar operations (such as getDeclName, getSchText). For example, DeclNamePrint will traverse AST and print the word-parts of all declaring names (DeclName)
  • To add this operation, define a new Visitor class first

Right Example

CZT (Community Z Tool) project uses the visitor pattern to separate the structure of a set of AST (Annotated Syntax Tree) node from the operations performed on these nodes.
  • CZT has the defined inheritance hierarchy, and different kinds of nodes, such as paragraph, schema, and reference.

Reference:

[Perl] Retrieve bug status from Bugzilla server

Bugzilla provides an initial script called bz_webservice_demo.pl which shows how to talk to Bugzilla via XMLRPC.
The option --bug_id can take one bug id as a parameter to the script, such as --bug_id 1212. So if we want to retrieve the status for multiple bugs, we have to call the script multiple times. It’s time consuming. It’s better to call the script once and retrieve the status for a list of bugs.
Look at the original code for the handle of bug_id. The web service method used to get status is called Bug.get.
  • The ids parameter is an array of numbers and strings. So we can pass multiple bugs together in ids.
  • Besides, this method can accept standard include_fields and exclude_fields arguments as well.

if ($bug_id) {
    $soapresult = $proxy->call('Bug.get', { ids => [$bug_id] });
    _die_on_fault($soapresult);
    $result = $soapresult->result;
    my $bug = $result->{bugs}->[0];
    foreach my $field (keys(%$bug)) {
        my $value = $bug->{$field};
        if (ref($value) eq 'HASH') {
            foreach (keys %$value) {
                print "$_: " . $value->{$_} . "\n";
            }
        }
        else {
            print "$field: $value\n";
        }
    }
}
My approach is to extend --bug_id to take a comma separate list of bugs, then convert the list to an array for the parameter ids. In addition, since I only want the status, I can use the include_fields to select the field status and id only.
  • Why need id field? Since we return the status for many bugs, we need to check which id is each status linked to.
Another question is about how to get the value of status and id fields from returns. The reference of Bug.get method shows
bugs: An array of hashes that contains information about the bugs with the valid ids. Each hash contains the following items:
id [int]: The unique numeric id of this bug.
status [string]: The current status of the bug.
We can use the perl debug to check the structure of return bugs.
  • run perl script in debug mode
    $ perl -d -e bz_webservice_demo.pl --uri https://mycompany.com/bugzilla/xmlrpc.cgi --bug_id 121,131,141
  • use b to set breakpoint
  • use r to run it
  • use x $result to show the result
Finally I use the following script to display the status for multiple bugs.
my @bugs;

if ($bug_id) {
    @bugs = split(/,/, $bug_id);
    my $b = $_;
    $soapresult = $proxy->call('Bug.get', { ids => [@bugs], include_fields => ['id', 'status']});
    _die_on_fault($soapresult);
    $result = $soapresult->result;
    my $bugs = $result->{bugs};
    foreach my $bug (@$bugs) {
        print "status: $bug->{id} $bug->{status}\n";
    }
}