1. 程式人生 > >Ns2中的測試用例

Ns2中的測試用例

  1測試用例說明NS2的原始碼包中包含了幾乎所有協議的測試程式碼,全部存放在ns2/tcl/test目錄下,即test-suite-*.tcl這樣的檔案。每個檔案基本就對應一個協議,而且有一個對應的輸出目錄存放供比較用的執行結果。在執行test-suite-*.tcl之後將會產生一個temp.rands檔案,只要這個檔案和相應目錄下的檔案比較相一致就說明NS2的安裝是正確的。test-suite-adaptive-red.tcl這個檔案的對應目錄就是test-output-adaptive-red。 每個測試用的tcl檔案中都使用了一個或多個測試用例,因此output目錄下也對應有一個或者多個檔案,這些供比較用的檔案都是用gzip壓縮的,比較前應先解壓縮。通過ns test-suite-*.tcl這樣的命令可以知道每個TCL檔案所支援的測試用例。使用ns test-suite-*.tcl test_name這樣的格式就可以呼叫指定的測試用例。
如 Ns test-suite-adaptive-red.tcl red1 就指明瞭要呼叫red1這個測試用例,執行之後在測試目錄下生成temp.rands檔案,將這個檔案與test-output-adaptive-red/red1.Z解壓縮後的檔案進行比較即可。 2測試程式碼 在此測試目錄下同時提供了完整的測試Shell程式碼,不過很遺憾在windows下沒法執行(需要cygwin),於是自己動手寫了下面的C++程式碼進行完整的測試。 // NsTest.cpp : 定義控制檯應用程式的入口點。 // #include "stdafx.h" #include <windows.h> #include
<fstream> #include <math.h> using namespace std; #define TEST_PATH "d://temp//test//" #define FIND_MASK "d://temp//test//test-suite-*.tcl" #define NS_PATH "d://research//debug//ns-2.31.exe" void Compare(char* f1, char* f2) {      // 比較兩個檔案是否相同,之所以不用cmp進行比較,是因為在不同版本生成的資料中輸出格式可能會不一致,      // 主要是科學計數法輸出的不一致,如提供的原始資料為.2e-05,而生成的資料為.2e-005
     ifstream s1(f1);      ifstream s2(f2);      if(s1.is_open() && s2.is_open())      {          char line1[2048], line2[2048];          int nLine = 0;          while(!s1.eof() && !s2.eof())          {               nLine++;               s1.getline(line1, 2048);               s2.getline(line2, 2048);               if(strcmp(line1, line2) == 0) continue;               double d[4];               sscanf(line1, "%lf %lf", &d[0], &d[1]);               sscanf(line2, "%lf %lf", &d[2], &d[3]);               if(fabs(d[0] - d[2]) > 0.00005 || fabs(d[1] - d[3]) > 0.005)               {                    printf("%s and %s compare failed: /nline: %d/n%s/n%s/n", f1, f2, nLine, line1, line2);                    s1.close();                    s2.close();                    exit(1);               }          }          if(s1.eof() && !s2.eof())          {               printf("%s and %s compare failed: s1.eof() && !s2.eof()", f1, f2);               s1.close();               s2.close();               exit(1);          }          else if(!s1.eof() && s2.eof())          {               printf("%s and %s compare failed: !s1.eof() && s2.eof()", f1, f2);               s1.close();               s2.close();               exit(1);          }      }      else      {          printf("compare file open failed: /n%s/n%s/n", f1, f2);          s1.close();          s2.close();          exit(1);      }      s1.close();      s2.close(); } void Exec(char *cmd) {      DWORD code = 0;      STARTUPINFO si;      PROCESS_INFORMATION pi;      ZeroMemory( &si, sizeof(si) );      si.cb = sizeof(si);      ZeroMemory( &pi, sizeof(pi) );      // Start the child process.      if( !CreateProcess( NULL,   // No module name (use command line).          cmd, // Command line.          NULL,             // Process handle not inheritable.          NULL,             // Thread handle not inheritable.          FALSE,            // Set handle inheritance to FALSE.          0,                // No creation flags.          NULL,             // Use parent's environment block.          TEST_PATH,             // Use parent's starting directory.          &si,              // Pointer to STARTUPINFO structure.          &pi )             // Pointer to PROCESS_INFORMATION structure.      )      {          printf( "%s failed (%d)./n", cmd, GetLastError() );          exit(1);      }      WaitForSingleObject( pi.hProcess, INFINITE );      GetExitCodeProcess(pi.hProcess, &code);      CloseHandle( pi.hProcess );      CloseHandle( pi.hThread );      if(code != 0)      {          printf("%s failed with code (%d)/n", cmd, code);          exit(code);      } } bool IsComment(char* p) {      while((*p == ' ' || *p == '/t') && *p != 0) p++;      return *p == '#'; } void ProcessOneFile(char* file_name) {      // 處理一個檔案      char tcl_file[MAX_PATH];      sprintf(tcl_file, "%stest-suite-%s.tcl", TEST_PATH, file_name);      ifstream src(tcl_file);      if(!src.is_open())      {          printf("%s open failed!/n", tcl_file);          return;      }      sprintf(tcl_file, "%s_tmp.tcl", TEST_PATH);      FILE* dst = fopen(tcl_file, "wt");      if(dst == NULL)      {          printf("create temp tcl failed/n");          src.close();          return;      }      fprintf(dst, "set PERL {perl}/n");      fprintf(dst, "set quiet true/n");      char cClass[1000][100];      int nClass = 0;      while(!src.eof())      {          char line[2048];          char* p;          src.getline(line, 2048);          if(IsComment(line)) continue;          if(strstr(line, "Class") && (p = strstr(line, "Test/")))          {               int idx = 0;               p += 5;               while(*p != 0 && *p != ' ') cClass[nClass][idx++] = *p++;               cClass[nClass][idx] = 0;               nClass++;          }          else if(strstr(line, "xgraph"))          {               fprintf(dst, "#");          }          fprintf(dst, "%s/n", line);      }      src.close();      fclose(dst);      // 執行TCL檔案並進行比較      for(int i = 0; i < nClass; i++)      {          printf("%s testcase begin...", cClass[i]);          char cmd[2560];          sprintf(cmd, "%s %s_tmp.tcl %s", NS_PATH, TEST_PATH, cClass[i]);          Exec(cmd);          // 備份壓縮檔案          sprintf(cmd, "cp %stest-output-%s//%s.Z %stest-output-%s//%s_bak.Z", TEST_PATH, file_name, cClass[i], TEST_PATH, file_name, cClass[i]);          Exec(cmd);          // 解壓縮          sprintf(cmd, "gzip -daf %stest-output-%s//%s.Z", TEST_PATH, file_name, cClass[i]);          Exec(cmd);          // 還原壓縮檔案          sprintf(cmd, "mv %stest-output-%s//%s_bak.Z %stest-output-%s//%s.Z", TEST_PATH, file_name, cClass[i], TEST_PATH, file_name, cClass[i]);          Exec(cmd);          // 比較檔案          char f1[MAX_PATH], f2[MAX_PATH];          sprintf(f1, "%stest-output-%s//%s", TEST_PATH, file_name, cClass[i]);          sprintf(f2, "%stemp.rands", TEST_PATH);          Compare(f1, f2);          // 刪除解壓縮後的檔案          sprintf(cmd, "rm -f %stest-output-%s//%s", TEST_PATH, file_name, cClass[i]);          Exec(cmd);          printf("OK/n");      } } int _tmain(int argc, _TCHAR* argv[]) {      // 查詢測試檔案所在目錄下的所有檔案      WIN32_FIND_DATA fdata;      HANDLE hFind = FindFirstFile(FIND_MASK, &fdata);      if(hFind == INVALID_HANDLE_VALUE)      {          printf("find file failed");          return 1;      }      do      {          bool bProcess = false;          if(argc > 1)          {               for(int i = 1; i < argc; i++)               {                    if(strstr(fdata.cFileName, argv[i]))                    {                        bProcess = true;                        break;                    }               }          }          else               bProcess = true;          if(bProcess)          {               printf("/n%s processing.../n", fdata.cFileName);               fdata.cFileName[strlen(fdata.cFileName) - 4] = 0;               ProcessOneFile(fdata.cFileName + strlen("test-suite-"));          }      }while(FindNextFile(hFind, &fdata));      FindClose(hFind);      printf("all file processed/n");      getchar();      return 0; } 3程式碼使用說明 1.在使用此程式碼進行測試前還必須安裝ActivePerl,gawk,UnxUtils這幾個軟體包並配置好相應的路徑。 2.然後修改misc-simple.tcl檔案,將其中 set quiet false 這行語句去掉,否則測試時將不斷呼叫xgraph,影響連續測試。 3.如果執行nstest不帶任何引數,則執行所有的測試直到測試出來錯誤。 也可以用nstest test_name這樣的方式呼叫,其中的test_name只要使用test-suite-*.tcl中的星號部分就可以了,如nstest adaptive-red。 4測試中發現的問題 有一些測試無法通過,估計是由於編譯器的差異引起的,如有一些測試生成的資料是5.623,而供比較用的資料是5.622,且只有一兩個地方不一致,因此在程式碼中做了處理,允許這種不一致。 再如3.2e-05和3.2e-005這樣的差異也認為不是錯誤。 另外有一些則差別很遠,如test-suite-broken.tcl,原因暫時不明,思考中。。。。。