Friday, June 29, 2018

Some flaw happened in clearing the memory

There is some amendment being done in clearMemory() for a very long time ago. I can't recall what I did last time, the code seemed likely been done in a rush and there are not test well. This is the piece I mention in this post:
void FileBot::clearMemory(FileNode *fileNode)
{
    bool lastNode = false;

    // this case will happened only when the root is supply
    if( fileList.size() == 0 || (fileList.begin())->sibling.empty() ) {
        BOOST_LOG_TRIVIAL(info) << "current node has no sibling: " << endl;
        return;
    }

    // if this is the only node in the container
    // clean up the container and then bail
    FileNode *firstNode = &*(fileList.begin());

    // test on first node is empty
    if( !firstNode->sibling.empty() && firstNode->sibling.size() == 0 ) {
        BOOST_LOG_TRIVIAL(info) << "This is the only node. Root size [" << fileList.size() << "]";
        fileList.erase_and_dispose(fileList.begin(), fileList.end(), DisposeFileNode());
        return;
    }

    // if this is not the only node in the container
    // clean up the container recursively
    if( fileNode == NULL ) {
       BOOST_LOG_TRIVIAL(info) << "current node has no sibling: " << fileNode;

       fileNode = &*(fileList.begin());
       fileList.erase_and_dispose(fileList.begin(), fileList.end(), DisposeFileNode());
       lastNode = true;
    }
    else {
        BOOST_LOG_TRIVIAL(info) << "current node has sibling: " << fileNode << " : " << fileNode->getName() << " sibling : " << fileNode->sibling.size();

        if( fileNode->sibling.size() > 0 ) {
            for( FileNodeListType::iterator it = fileNode->sibling.begin(); it != fileNode->sibling.end(); it++ ) {
                clearMemory(&*(it));
            }
        }
        else {
            cout << fileNode << " has no more sibling." << endl;
            return;
        }

        BOOST_LOG_TRIVIAL(info) << "cleaning sibling memory for this node: " << fileNode << " node name: " << fileNode->getName();
        fileNode->sibling.erase_and_dispose(fileNode->sibling.begin(), fileNode->sibling.end(), DisposeFileNode());
    }

    if( lastNode ) {
        BOOST_LOG_TRIVIAL(info) << "Reacing the root. Root size [" << fileList.size() << "]";
        fileList.erase_and_dispose(fileList.begin(), fileList.end(), DisposeFileNode());
    }
}
In the past few days I sat down just to review my test case, I found out some of the code was not covered by the test cases. Those uncover pieces are 16-20, 24-30, and 49-52. I was shocked when I see those uncovered pieces. I wonder whether those pieces are unused code since none of the test cases cover them up.

I study the code carefully, test run for few times and finally I got a fantastic conclusion. There are 2 sections are required for this function to carry on its job; first section would be the validation, this will validate whether the container, as well as, the FileNode's sibling contain any elements in it? This is the one:
    // this case will happened only when the root is supply
    if( fileList.size() == 0 || (fileList.begin())->sibling.empty() ) {
        BOOST_LOG_TRIVIAL(info) << "current node has no sibling: " << endl;
        return;
    }
Whereas the second section would be the core logic focus on cleaning the container, as well as, the sibling of each FileNode. Here is the one:
    BOOST_LOG_TRIVIAL(info) << "current node has sibling: " << fileNode << " : " << fileNode->getName() << " sibling : " << fileNode->sibling.size();

    if( fileNode->sibling.size() > 0 ) {
        for( FileNodeListType::iterator it = fileNode->sibling.begin(); it != fileNode->sibling.end(); it++ ) {
            clearMemory(&*(it));
        }
    }
    else {
         cout << fileNode << " has no more sibling." << endl;
         return;
    }

    BOOST_LOG_TRIVIAL(info) << "cleaning sibling memory for this node: " << fileNode << " node name: " << fileNode->getName();
    fileNode->sibling.erase_and_dispose(fileNode->sibling.begin(), fileNode->sibling.end(), DisposeFileNode());
Now the code is much more readable. Don't you agree? Oh! by the way, I already moved this function into the destructor since I'll invoke this function at the end of each unit test. Don't you feel much better?
FileBot::~FileBot()
{
    clearMemory(&*(fileList.begin()));
}

Invocation WsimportTool failed?!!

Hey there, I am making a new friend today. The meet this new friend in Eclipse Photon when I was creating a brand new web service project. Here is the story, when I first started the project, I only have the WSDL file ready in the source folder, and then I have the jaxws-maven-plugin in my pom file, like this:
  <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>jaxws-maven-plugin</artifactId>
    <version>2.5</version>
    <executions>
      <execution>
        <goals>
          <goal>wsimport</goal>
        </goals>
        <configuration>
          <keep>true</keep>
          <extension>true</extension>
          <sourceDestDir>${basedir}/src/main/java</sourceDestDir>
          <packageName>org.huahsin68.ws</packageName>
          <wsdlDirectory>${basedir}/src/main/resources</wsdlDirectory>
          <wsdlFiles>
            <wsdlFile>hello.wsdl</wsdlFile>
          </wsdlFiles>
        </configuration>
      </execution>
    </executions>
  </plugin>
Then this error immediately shown up right after the execution tag as shown below. What was that mean? I don’t even understand why the WsimportTool could fail?
Invocation of com.sun.tools.ws.wscompile.WsimportTool failed - check output (org.codehaus.mojo:jaxws-maven-plugin:2.5:wsimport:default:generate-sources)

org.apache.maven.plugin.MojoExecutionException: Invocation of com.sun.tools.ws.wscompile.WsimportTool failed - check output
 at org.codehaus.mojo.jaxws.AbstractJaxwsMojo.exec(AbstractJaxwsMojo.java:485)
 at org.codehaus.mojo.jaxws.WsImportMojo.processLocalWsdlFiles(WsImportMojo.java:339)
 at org.codehaus.mojo.jaxws.WsImportMojo.executeJaxws(WsImportMojo.java:292)
 at org.codehaus.mojo.jaxws.MainWsImportMojo.executeJaxws(MainWsImportMojo.java:54)
 at org.codehaus.mojo.jaxws.AbstractJaxwsMojo.execute(AbstractJaxwsMojo.java:386)
 at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:137)
 at org.eclipse.m2e.core.internal.embedder.MavenImpl.execute(MavenImpl.java:331)
 at org.eclipse.m2e.core.internal.embedder.MavenImpl$11.call(MavenImpl.java:1362)
 at org.eclipse.m2e.core.internal.embedder.MavenImpl$11.call(MavenImpl.java:1)
 at org.eclipse.m2e.core.internal.embedder.MavenExecutionContext.executeBare(MavenExecutionContext.java:177)
 at org.eclipse.m2e.core.internal.embedder.MavenExecutionContext.execute(MavenExecutionContext.java:112)
 at org.eclipse.m2e.core.internal.embedder.MavenImpl.execute(MavenImpl.java:1360)
 at org.eclipse.m2e.core.project.configurator.MojoExecutionBuildParticipant.build(MojoExecutionBuildParticipant.java:52)
 at org.eclipse.m2e.core.internal.builder.MavenBuilderImpl.build(MavenBuilderImpl.java:137)
 at org.eclipse.m2e.core.internal.builder.MavenBuilder$1.method(MavenBuilder.java:172)
 at org.eclipse.m2e.core.internal.builder.MavenBuilder$1.method(MavenBuilder.java:1)
 at org.eclipse.m2e.core.internal.builder.MavenBuilder$BuildMethod$1$1.call(MavenBuilder.java:115)
 at org.eclipse.m2e.core.internal.embedder.MavenExecutionContext.executeBare(MavenExecutionContext.java:177)
 at org.eclipse.m2e.core.internal.embedder.MavenExecutionContext.execute(MavenExecutionContext.java:112)
 at org.eclipse.m2e.core.internal.builder.MavenBuilder$BuildMethod$1.call(MavenBuilder.java:105)
 at org.eclipse.m2e.core.internal.embedder.MavenExecutionContext.executeBare(MavenExecutionContext.java:177)
 at org.eclipse.m2e.core.internal.embedder.MavenExecutionContext.execute(MavenExecutionContext.java:151)
 at org.eclipse.m2e.core.internal.embedder.MavenExecutionContext.execute(MavenExecutionContext.java:99)
 at org.eclipse.m2e.core.internal.builder.MavenBuilder$BuildMethod.execute(MavenBuilder.java:86)
 at org.eclipse.m2e.core.internal.builder.MavenBuilder.build(MavenBuilder.java:200)
 at org.eclipse.core.internal.events.BuildManager$2.run(BuildManager.java:795)
 at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
 at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:216)
 at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:259)
 at org.eclipse.core.internal.events.BuildManager$1.run(BuildManager.java:312)
 at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
 at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:315)
 at org.eclipse.core.internal.events.BuildManager.basicBuildLoop(BuildManager.java:367)
 at org.eclipse.core.internal.events.BuildManager.build(BuildManager.java:388)
 at org.eclipse.core.internal.events.AutoBuildJob.doBuild(AutoBuildJob.java:142)
 at org.eclipse.core.internal.events.AutoBuildJob.run(AutoBuildJob.java:232)
 at org.eclipse.core.internal.jobs.Worker.run(Worker.java:60)
Googling the around some said that this is a defect from the IDE; some even said that this could be caused by the JAVA version issue; some even said JDK 8 is not supported in Eclipse Mars version. Does it true? Not really. Firstly, I issued a command mvn clean and then follow by mvn generate-sources. The error is gone! What a weird day?!!

Sunday, June 24, 2018

Verifying the "files" are being loaded correctly

I'd made a function that its sole responsibility is to verify the files have successfully loaded into memory. Following code snippet shows my hard work:
std::list<string> FileBot::getLoadedFiles(FileNode *fileNode)
{
    std::list<string> mlist;

    BOOST_LOG_TRIVIAL(info) << "current root address : " << fileNode;

    if( fileNode == nullptr || fileNode->sibling.size() == 0 )
        return mlist;

    for( FileNodeListType::iterator it = fileNode->sibling.begin(); it != fileNode->sibling.end(); ++it )
    {
        FileNode *n = (&*it);

        if( n->getType() == 'd' ) {
            std::list<string> subList;
            subList = getLoadedFiles(n);

            mlist.insert(mlist.begin(), subList.begin(), subList.end());
        }
        else {
            string filePath = constructPathAddress(n);
            mlist.push_back(filePath);

            BOOST_LOG_TRIVIAL(info) << "filePath : " << filePath;
        }
    }

    return mlist;
}
I need this function in my unit test code to ensure constructParentPath() and constructChildPath() are doing their job correctly. Take the following test case for example:
BOOST_AUTO_TEST_CASE(TL_5, *boost::unit_test::precondition(skipTest(true)))
{
    BOOST_TEST_MESSAGE("TC8 : one file is captured without sub folder");

    string testPathA = current_path().string() + string(1, path::preferred_separator) + "FolderA";
    createTestFile(testPathA, 1);

#if defined(WIN32)
    BOOST_TEST(testPathA == "D:\\workspaceqt\\backupUtil\\backupUtilUnitTest\\FolderA");
#else
    BOOST_TEST(testPathA == "/home/kokhoe/workspaceqt/debug/FolderA");
#endif

    FileBotUnderTest fb;
    FileNode *root = nullptr;
    if( (root = fb.constructParentPath(testPathA)) == nullptr ) {
        BOOST_TEST_MESSAGE("Initialization failed.");
        return;
    }

    string path = fb.getParentPathAddress();

#if defined(WIN32)
    BOOST_TEST(path == "D:\\workspaceqt\\backupUtil\\backupUtilUnitTest\\FolderA\\");
#else
    BOOST_TEST(path == "/home/kokhoe/workspaceqt/debug/FolderA/");
#endif

    fb.constructChildPath(root);

    // verify the file name was captured
    std::list<string> files = fb.getLoadedFiles(root);

    BOOST_TEST(files.size() == 1);

#if defined(WIN32)
    if( std::find(files.begin(), files.end(), "D:/workspaceqt/backupUtil/backupUtilUnitTest/FolderA/file_1.txt") == files.end() )
        BOOST_TEST(false);
#else
    if( std::find(files.begin(), files.end(), "/home/kokhoe/workspaceqt/debug/FolderA/file_1.txt") == files.end() )
        BOOST_TEST(false);
#endif

    destroyTestFile(testPathA);
}
This function is gets invoked right after the "files" are loaded into memory. There are not the physical file, it's just a shadow. To effectively process the files stored in the sub folder, it will invoke itself to dive into the sub folder bringing together a reference of the current path, until it has iterated through the end of the path. That is the reason why this function has a parameter of FileNode type. But there was a question come into my mind, why do I still need to pass the root (a reference value came from constructParentPath() in the unit test mention above) into this function since the FileBot class already got a reference to this value?
class FileBot
{
   ...
   ...

private:
    // *root should never be NULL
    FileNode *root = nullptr;       // store the a reference to root path

}
I know this was stupid. The initial objective is to create a function that could verify the "files" that has been loaded into memory are done correctly. I think this function is only used for the unit test purpose. I'll just leave it as it is.

Tuesday, June 19, 2018

Making a contract first web service with Spring Boot

I have been told that Spring Boot is a great tool to learn. What do I think? In order to get my hand dirty on that, I've chosen to use it to develop a web service project. Well, I'd spend almost an hour plus to launch a web service, able to accept a request and provide a response. It was really damn amazing.

Unlike the tutorial I found on the Internet, my job scope doesn't work in that way. It is the WSDL file was created first, a.k.a. contract-first, but the tutorial I found on the Internet are contract-last. Wait, there are still hope, I found following sample that could help out.

Sample 1
@EnableWs
@Configuration
public class WebServiceConfig extends WsConfigurerAdapter
{
   @Bean(name = "services")
   public Wsdl11Definition defaultWsdl11Definition() {
      SimpleWsdl11Definition wsdl11Definition = new SimpleWsdl11Definition();
      wsdl11Definition.setWsdl(new ClassPathResource("/schema/MyWsdl.wsdl")); //your wsdl location
      return wsdl11Definition;
   }
}
Sample 2
@EnableWs
@Configuration
public class WebServiceConfig extends WsConfigurerAdapter
{
   @Bean(name = "wsdlname")
   public DefaultWsdl11Definition defaultWsdl11Definition (XsdSchema cityRequestSchema) {
      DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
      wsdl11Definition.setRequestSuffix("ByCountry");
      wsdl11Definition.setResponseSuffix("City");
      wsdl11Definition.setPortTypeName("Hotelport");
      wsdl11Definition.setLocationUri("/ProjectName");
      wsdl11Definition.setTargetNamespace("http://spring.io/guides/gs-producing-web-service");
      wsdl11Definition.setSchema(cityRequestSchema);
      return wsdl11Definition;
   }

   @Bean
   public XsdSchema cityRequestSchema() {
      return new SimpleXsdSchema(new ClassPathResource("CityRequest.xsd"));
   }
}
Wait, I'm looking at the DefaultWsdl11Definition class, which I felt kind of weird, it doesn't seem sound right to me. Is it going to create the WSDL specification version 1.1, but my version is 1.2. I don't think this will work. Wait, the story has not ended, after a few days of searching, I manage to find a tutorial which has done a very good job on this matter. There are 2 ways to do this:

First solution
Do it in Spring configuration and load this configuration in the main class.
<beans xmlns="http://www.springframework.org/schema/beans" 
 xmlns:context="http://www.springframework.org/schema/context" 
 xmlns:jaxws="http://cxf.apache.org/jaxws" 
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                     http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
                     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

   <context:component-scan base-package="org.huahsin68.core"/>

   <jaxws:endpoint 
      id="HelloService" 
      implementor="#helloResponseImpl"
      serviceName="s:HelloService"
      address="/hello"
      xmlns:s="http://huahsin68.org/helloService>
      <jaxws:features>
         < bean class="org.apache.cxf.ext.logging.LoggingFeature"/>
      </jaxws:features>
   </jaxws:endpoint> 
</beans>
@SpringBootApplication
@ImportResource({"classpath:beans.xml"})
public class Application {
   ...
   ...
}
Second solution
Do it in Java. Create an Endpoint bean inside the configuration bean.
@Configuration
public class WebServiceConfig {

   ...
   ...

   @Bean
   public Endpoint endpoint() {
      HelloService h = new HelloService();
      EndpointImpl endpoint = new EndpointImpl(springBus(), new InfoServiceImpl());

      endpoint.getFeatures().add(new LoggingFeature());
      endpoint.setWsdlLocation("classpath:hello.wsdl");
      endpoint.setServiceName(h.getServiceName());
      endpoint.publish("/hello");

      return endpoint;
   }
}

Reference:
Building soap web service with Apache CXF and Spring Boot

Friday, June 1, 2018

Maven unable to find valid certification path

Here is the most useful command that could help clean up the mess in Maven.
mvn –U clean compile
Unfortunately, that command is giving me a nasty error complaining that Maven was not able to find a valid certificate. WHAT THE HELL?
[ERROR] Plugin org.apache.maven.plugins:maven-compiler-plugin:3.7.0 or one of its dependencies could not be resolved: 
Failed to read artifact descriptor for org.apache.maven.plugins:maven-compiler-plugin:jar:3.7.0: Could not transfer artifact org.apache.maven.plugins:maven-plugins:pom:30 
from/to central (https://repo.maven.apache.org/maven2): sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: 
unable to find valid certification path to requested target -> [Help 1]
Will this error coming from the network firewall failure? If I read the details closely, this gives me a sense that my PC have not trusted the certificate for the site. In order to proceed the compilation, I must first trust the certificate, but how? I have no idea on dealing with Maven’s security issue during my past working experience. Spending hours on this issue and found this workaround from the Internet. First, follow the following steps to download the certificate and then import the certificate into a self-made keystore:
  1. Use a browser to go to https://repo.maven.apache.org/
  2. Click on lock icon and choose "View Certificate" 
  3. Go to the "Details"
  4. tab and choose "Save to File" Choose type "Base 64 X.509 (.CER)" and save it as mavenCert.cer 
  5. keytool -import -file mavenCert.cer -keystore mavenkeystore 
Once done, compile using following command:
mvn –U clean compile -Djavax.net.ssl.trustStore=mavenkeystore
From now on, whenever I need to download a new artifact from the maven repository or to do a clean build, I am required to use the command mention above instead of mvn –U clean compile.

Reference

Wednesday, May 16, 2018

Configure MinGW in Visual Studio Code

Just make some time for me to try out the tool - Visual Studio Code (VSC). It is a new toy from Microsoft. This writing was mainly for Windows platform targeted on MinGW compiler because I found out the setup in Windows is far more "complicated" than Linux. I think this is very rare for people living in the Windows world, but using MinGW as the primary compiler. Basically, there 3 configurations needed for my use case: c_cpp_properties.json, tasks.json, and launch.json.

c_cpp_properties.json

Linux was working fine without this file, but I am not sure why this file is needed for Windows. This file basically tells the tool how those declarations/definitions are resolved in the source file. Since I’m working on Windows, I will only focus on Win32 section. In my case, I need to tell the editor that I got extra MinGW header files located in other path. These paths are added into includePath. compilerPath tell the VSC where the compiler is located, unless the path has been added to the environment variable, then this field is optional. The default intelliSenseMode value was set to msvc-x64. It has to be changed to clang-x64 because this will throw a bunch of error on the std namespace declaration. The code snippet below shows the affected section:
{
    "configurations": [
        {
            "name": "Win32",
            "compilerPath": "C:/MinGW/bin/g++.exe",
            "includePath": [
                "C:/MinGW/include",
                "C:/MinGW/lib/gcc/mingw32/6.3.0/include",
                "C:/MinGW/lib/gcc/mingw32/6.3.0/include/c++",
                "C:/MinGW/lib/gcc/mingw32/6.3.0/include/c++/tr1",
                "C:/MinGW/lib/gcc/mingw32/6.3.0/include/c++/mingw32",
                "C:/tool/gsoap-2.8.55/gsoap",
                "${workspaceFolder}"
            ],
            "defines": [
                "_DEBUG",
                "UNICODE",
                "_UNICODE"
            ],
            "intelliSenseMode": "clang-x64",
            "browse": {
                "path": [
                    "${workspaceFolder}"
                ],
                "limitSymbolsToIncludedHeaders": true,
                "databaseFilename": ""
            },
            "cStandard": "c11",
            "cppStandard": "c++17"
        }
    ],
   … 
   …
}

tasks.json 

This file is to tell how the source is going to build. Before the file is created, I’m using the following command to build the source.
g++ -o main.exe main.cpp soapC.cpp soapServiceProxy.cpp c:/tool/gsoap-2.8.55/gsoap/stdsoap2.cpp 
-I. -Ic:/tool/gsoap-2.8.55/gsoap 
-Lc:/MinGW/lib -Lc:/MinGW/lib/gcc/mingw32/6.3.0 
-lws2_32 
-std=c++11
In the configuration file, the value of args is reflecting the command. But sometimes when the error occurred, I’ll go back to the command line to do a few rounds of testing to ensure it is working before come to the final configuration. Sometimes the build may not reflect on the latest changes, just close and reopen the VSC will resolve the issue.
"tasks": [
        {
            "label": "build testlab",
            "type": "shell",
            "command": "g++",
            "args": [
                "-g", 
                "-o", "main.exe",
                "main.cpp soapC.cpp soapServiceProxy.cpp c:/tool/gsoap-2.8.55/gsoap/stdsoap2.cpp",
                "-Ic:/tool/gsoap-2.8.55/gsoap",
                "-I.",
                "-Lc:/MinGW/lib",
                "-Lc:/MinGW/lib/gcc/mingw32/6.3.0",
                "-lws2_32",
                "-std=c++11"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        }
    ]

launch.json 

This file is to tell whether the program will start in debug mode or not. Basically, this file is ready to use when it was first generated, I just update the program field point to my program name, which is main.exe.
"configurations": [
    {
        "name": "(gdb) Launch",
        "type": "cppdbg",
        "request": "launch",
        "program": "${workspaceFolder}/main.exe",
        "args": [],
        "stopAtEntry": true,
        "cwd": "${workspaceFolder}",
        "environment": [],
        "externalConsole": true,
        "MIMode": "gdb",
        "miDebuggerPath": "C:/MinGW/bin/gdb.exe",
        "setupCommands": [
            {
                "description": "Enable pretty-printing for gdb",
                "text": "-enable-pretty-printing",
                "ignoreFailures": true
            }
        ]
    }
]

Saturday, May 5, 2018

Unit test code strategy on private method

During the initial development, the code was driven by the TDD concept. Thus, I have the following code published to the world temporarily. The 2 methods are the primary methods of this program; neither one of them missing will not work.
public:
    FileNode* constructParentPath(boost::filesystem::path inputPath);
    void constructChildPath(FileNode *currentRootNode);

    ...
    ...
This design was to make sure that I have enough test coverage for each method. After unit testing have been done, I have a plan to change the visibility of that 2 primary methods to private, and replace them with a more meaningful method. The new design would look like below:
public:
    FileNode* constructAbstractPath(boost::filesystem::path inputPath);


protected:
    FileNode* constructParentPath(boost::filesystem::path inputPath);
    void constructChildPath(FileNode *currentRootNode);


FileNode* FileBot::constructAbstractPath(boost::filesystem::path inputPath)
{
    constructParentPath(inputPath);
    constructChildPath(root);

    return root;
}
Ahhaa~ Feeling so nice with this method now. But the flip site of this change will spoil my existing unit test code. Thus, I think of a new solution that wouldn't make such a huge change while adapting the new design. I made a new class that mimics the existing method call as shown in below:
class FileBotUnderTest : public FileBot
{
public:
    FileBotUnderTest();

    FileNode* constructParentPath(boost::filesystem::path inputPath) {
        return FileBot::constructParentPath(inputPath);
    }

    void constructChildPath(FileNode *currentRootNode) {
        return FileBot::constructChildPath(currentRootNode);
    }
};
Changes in unit test code are very minimal, instead of interacting with FileBot, I'll just interact with FileBotUnderTest. Below are the work done for these changes:
BOOST_AUTO_TEST_CASE(TL_6, *boost::unit_test::precondition(skipTest(true)))
{
    BOOST_TEST_MESSAGE("TC6 : load 3 level parent path");
    string path = "";
    FileBotUnderTest fb;

#if defined(WIN32)
    BOOST_TEST_MESSAGE("Test path: D:\\workspaceqt\\ui1");
    path = "D:/workspaceqt/ui1";
#else
    BOOST_TEST_MESSAGE("Test path: /home/kokhoe/workspaceqt");
    path = "/home/kokhoe";
#endif

    if( fb.constructParentPath(path) != nullptr )
       path = fb.getParentPathAddress();

#if defined(WIN32)
    BOOST_TEST(path == "D:\\workspaceqt\\ui1\\");
    fb.clearMemory();
#else
    BOOST_TEST(path == "/home/kokhoe/");
#endif
}