c++與Tcl通過管道通訊,並傳遞引數,獲取測試儀實時測試進度

Augusdi發表於2015-08-22


目前,我在做測試自動化的專案,要用到smartbits,bps,testcenter和mu測試儀。通過呼叫測試儀提供的TCL API操作測試儀,從而實現測試用例的具體流程。我們用測試儀測試TOE時,會發現測試儀上會顯示測試進度(1%,2%...)。以Bps為例,當執行到set objectName [$testObjectName run

-progress "bps::textprogress stdout"]命令時,就會在螢幕上同步輸出當前的測試進度。為了與其他模組方便通訊,我利用c++呼叫TCL指令碼來實現用例。為了將tcl輸出的測試進度獲取並傳遞給其他模組,我利用windows API CreateProcess(),在c++與TCL指令碼之間開闢了一條管道。下面是我的.tcl原始碼和c++原始碼,希望對從事這方面開發的同仁有益。

【.tcl】

set dir [file dirname [info script]]
lappend auto_path $dir

wm withdraw .


proc testProc {ip uname pwd} {

 

puts "loading bps package..."
package require bps
puts "bps package loading complete."

set var [bps::connect $ip $uname $pwd]
set test1 [$var createTest]
set comName [$test1 createComponent bitblaster bb41 1 2]

puts "test running.."
set fid [open "testProgress.txt" w+]
if [catch {open "testProgress.txt" w+} $fid] {
puts stderr "cann't open "testProgress.txt" w+: $fid"
} else {

set reObj [$test1 run -progress "bps::textprogress stdout"]
puts $fid $reObj
close $fid
}


puts "quit"

}

#------------------------------------------------------------------
# Analyze cmd options
#set proc_list [ info commands ]
#for { set i 0 } { $i < $::argc } { incr i } {
#    if { -1 != [ lsearch -exact $proc_list [ lindex $::argv $i ] ] } {
#        puts "Try to execute proc '[ lindex $::argv $i ]' ......"
#       eval [ lindex $::argv $i ]
#   }
#}

#-----------------------------------------------------------------
# Analyze cmd options
set proc_list [ info commands ]
for { set i 0 } { $i < $::argc } { incr i } {
    set proc_name [ lindex $::argv $i ]
    if { [ expr [ regexp -- {^-} $proc_name ] && \
    -1 != [ lsearch -exact $proc_list [ string range $proc_name 1 end ] ] ] } {
        set param_list ""
        for { set j [ expr $i+1 ] } { $j < $::argc } { incr j } {
            set param_name [ lindex $::argv $j ]
            if { ![ regexp -- {^-} $param_name ] } {
                lappend param_list $param_name
            } else {
                set i [ expr $j - 1 ]
                break
            }
        }
        puts "Try to execute proc '[ string range $proc_name 1 end ]' with params '$param_list' ......"
        set eval_code [ list [ string range $proc_name 1 end ] ]
        foreach param $param_list { lappend eval_code $param }
        eval $eval_code
    }
}

【注】:如果testProc不需要引數,則可以將兩條“————”之間的程式碼解註釋,將“----”下面的程式碼註釋掉即可。

【c++】

#include "stdafx.h"
#include <Windows.h>
#include <string>
#include <process.h>
#include <iostream>
#include <stdio.h>
#include "tcl.h"
#include "tclDecls.h"
#pragma comment(lib,"tcl85.lib")
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
 


 SECURITY_ATTRIBUTES sa;
 HANDLE hRead,hWrite;

 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
 sa.lpSecurityDescriptor = NULL;
 sa.bInheritHandle = TRUE;
 if (!CreatePipe(&hRead,&hWrite,&sa,0)) {
  cout<<"Error On CreatePipe()"<<endl;
  return 0;
 }
 STARTUPINFO si;
 PROCESS_INFORMATION pi;
 si.cb = sizeof(STARTUPINFO);
 GetStartupInfo(&si);
 si.hStdError = hWrite;
 si.hStdOutput = hWrite;
 si.wShowWindow = SW_HIDE;
 si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
 string str1 = "D:\\Tcl\\bin\\wish85.exe test.tcl";
 string str2 = "-";
 string str3 = "test";
 string str4 = "10.10.0.1";
 string str6 = " ";
 string str7 = "mobei";
 string str8 = "mobei";
 string str = str1+str6+str2+str3+str6+str4+str6 + str7 + str6 + str8;
 
 char* strC = const_cast<char*>(str.c_str());

 if (!CreateProcess(NULL,strC, NULL,NULL,TRUE,NULL,NULL,NULL,&si,&pi))
 {
   cout<<"Error on CreateProcess()"<<endl;
   return 0;
 }
 CloseHandle(hWrite);

 char buffer[4096] = {0};
 DWORD bytesRead;
 while (true)
 {
  if (ReadFile(hRead,buffer,4095,&bytesRead,NULL) == NULL)
  {
   cout<<"test"<<endl;
   break;
  }
  else
  {
   string bufStr;
   bufStr = buffer;
   
   
   if (bufStr.find("quit") != -1)
   {
    break;
   }
   else
   {
     sendInfo(bufStr);//將測試進度傳送給其他模組
    cout<<"content of buffer is: "<<buffer<<endl;
   }
  }
  
 }
 cout<<"hello world"<<endl;
 

 
 
 return 0;
}

由於ReadFile()是個阻塞函式,所以在tcl指令碼里面輸出一個字元,當在bufStr中找到這個字元時就退出迴圈,這裡我輸出的是quit,作為退出迴圈標誌。測試的結果,我分別儲存在了兩個.txt檔案中,可以通過分析檔案獲取,下面是用c++讀取.txt檔案的程式碼。

【readTxt】

// readTxt.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"


#include "iostream"
#include <fstream >
#include <string>

using namespace std;
string readTxt(string fileName);

int main(int argc, char* argv[])
{
  string result = readTxt("passorfailed.txt");
 cout<<"result is: "<<result<<endl;
 if (result == "passed")
 {
  cout<<"test ok"<<endl;
 }
 else
  cout<<"test failed"<<endl;
 return 0;
}


string readTxt(string fileName)
{
 ifstream infile;
 char* fileNamePtr = const_cast<char*>(fileName.c_str());

 infile.open (fileNamePtr);
 if(!infile)
  cout<<"error"<<endl;   //判斷檔案是被成功開啟
 string num;             //定義檔案中的資料型別
 char p;                 //定義一個字元讀取檔案中的空格和/或回車符
 int M=1;               //這裡首先定義為1是因為最後一行的結束符是EOF,所以用'\n'來判斷行的話,                   //最後一行會漏悼。所以先把它定義為1,也就相當於加上了最後一行!
 int N=0;
 while(!infile.eof())   //每次讀入之前都要判斷是否到了檔案末
 {
  do{
   infile.get (p);
   if(p=='\n')
   {
    M++;         //統計行數;
    N=0;        //一個新行開始時,列數置為0
    cout<<endl; //一行之後輸出一個換行符
   }
  }while(isspace((int)p) && !infile.eof ());//結束條件是讀入的是空格或已到達檔案末
  N++;                 //統計列數
  infile.putback (p); // 如果前面讀入的不是空格或回車符,則要把剛才讀入的字元返回到檔案流中!
  infile>>num;        //   讀入一個數
  cout<<num<<" ";    //   輸出剛才讀入的資料
 }
 infile.close (); //     關閉檔案

 return num;
}

 

如果從事過這方面開發的同仁有更好的解決方案,歡迎不吝賜教。

相關文章