2009-08-18 8 views
0

私は何かのポインタの問題を抱えていると私は書いている単体テストを持っています。基本的には、いったん構築されると、ファイルに関する情報を返すクラスをテストしています。予想されるすべてのファイルが検出された場合、テストは正しく動作します。検出されるよりも多くのファイルが存在すると、ルーチンは正しくエラーを報告します。しかし、予想より多くのファイルが検出された場合、実行可能ファイルはクラッシュします。これは、私がデバッガをステップスルーしようとすると、現在のコードポイントがメソッド全体にジャンプするため、これは難しいものでした。アプリケーションでの奇妙な実行エラー

私が間違ってやっていることについてのアイデアはありますか?

ここに私のコードは次のとおりです。

#include "stdafx.h" 
#include "boostUnitTest.h" 

#include "../pevFind/fileData.h" //Header file for tested code. 
#include "../pevFind/stringUtil.h" //convertUnicode() 

struct fileDataLoadingFixture 
{ 
    std::vector<fileData> testSuiteCandidates; 
    fileDataLoadingFixture() 
    { 
     WIN32_FIND_DATA curFileData; 
     HANDLE fData = FindFirstFile(L"testFiles\\*", &curFileData); 
     if (fData == INVALID_HANDLE_VALUE) 
      throw std::runtime_error("Failed to load file list!"); 
     do { 
      if(boost::algorithm::equals(curFileData.cFileName, L".")) continue; 
      if(boost::algorithm::equals(curFileData.cFileName, L"..")) continue; 
      fileData theFile(curFileData, L".\\testFiles\\"); 
      testSuiteCandidates.push_back(theFile); 
     } while (FindNextFile(fData, &curFileData)); 
     FindClose(fData); 
    }; 
}; 

BOOST_FIXTURE_TEST_SUITE(fileDataTests, fileDataLoadingFixture) 

BOOST_AUTO_TEST_CASE(testPEData) 
{ 
    std::vector<std::wstring> expectedResults; 
    expectedResults.push_back(L"a.cfexe"); 
    expectedResults.push_back(L"b.cfexe"); 
    //More files.... 
    expectedResults.push_back(L"c.cfexe"); 
    std::sort(expectedResults.begin(), expectedResults.end()); 
    for (std::vector<fileData>::const_iterator it = testSuiteCandidates.begin(); it != testSuiteCandidates.end(); it++) 
    { 
     if (it->isPE()) 
     { 
      std::wstring theFileString(it->getFileName().substr(it->getFileName().find_last_of(L'\\') + 1)); 
      std::vector<std::wstring>::const_iterator target = std::lower_bound(expectedResults.begin(), expectedResults.end(), theFileString); 
      BOOST_REQUIRE_MESSAGE(*target == theFileString, std::string("The file ") + convertUnicode(theFileString) + " was unexpected."); 
      if (*target == theFileString) 
      { 
       expectedResults.erase(target); 
      } 
     } 
    } 
    BOOST_CHECK_MESSAGE(expectedResults.size() == 0, "Some expected results were not found."); 
} 

BOOST_AUTO_TEST_SUITE_END() 

ありがとう!

Billy3

私の代わりに、次のコードを使用して問題を解決:

BOOST_AUTO_TEST_CASE(testPEData) 
{ 
    std::vector<std::wstring> expectedResults; 
    expectedResults.push_back(L"blah.cfexe"); 
    //files 
    expectedResults.push_back(L"tail.cfexe"); 
    expectedResults.push_back(L"zip.cfexe"); 
    std::vector<std::wstring> actualResults; 
    for(std::vector<fileData>::const_iterator it = testSuiteCandidates.begin(); it != testSuiteCandidates.end(); it++) 
    { 
     if (it->isPE()) actualResults.push_back(it->getFileName().substr(it->getFileName().find_last_of(L'\\') + 1)); 
    } 

    std::sort(expectedResults.begin(), expectedResults.end()); 
    std::sort(actualResults.begin(), actualResults.end()); 

    std::vector<std::wstring> missed; 
    std::set_difference(expectedResults.begin(), expectedResults.end(), actualResults.begin(), actualResults.end(), std::back_inserter(missed)); 

    std::vector<std::wstring> incorrect; 
    std::set_difference(actualResults.begin(), actualResults.end(), expectedResults.begin(), expectedResults.end(), std::back_inserter(incorrect)); 

    for(std::vector<std::wstring>::const_iterator it = missed.begin(); it != missed.end(); it++) 
    { 
     BOOST_ERROR(std::string("The file ") + convertUnicode(*it) + " was expected but not returned."); 
    } 

    for(std::vector<std::wstring>::const_iterator it = incorrect.begin(); it != incorrect.end(); it++) 
    { 
     BOOST_ERROR(std::string("The file ") + convertUnicode(*it) + " was returned but not expected."); 
    } 

    BOOST_CHECK(true); //Suppress commandline "No assertions" warning 

} 

答えて

2

あなたは、このファイルが予想外だった場合に、戻りますどう思いますか?あなたがそれが有効なファイル名であると思われるようです。

std::vector<std::wstring>::const_iterator target = std::lower_bound(expectedResults.begin(), expectedResults.end(), theFileString); 

それは実際には配列の最後過去1でイテレータになります - あなたは有効なポインタとして扱うことはできません。

BOOST_REQUIRE_MESSAGE(*target == theFileString, std::string("The file ") + convertUnicode(theFileString) + " was unexpected."); 

Normall、あなたはend()の値との結果を比較します(固定):

BOOST_REQUIRE_MESSAGE(target != expectedResults.end() || *target == theFileString, std::string("The file ") + convertUnicode(theFileString) + " was unexpected."); 
if (target != expectedResults.end() && *target == theFileString) 
{ 
    expectedResults.erase(target); 
} 

this example hereで参照lower_boundオフ次いで、終了値が返されます。

int main() 
{ 
    int A[] = { 1, 2, 3, 3, 3, 5, 8 }; 
    const int N = sizeof(A)/sizeof(int); 

    for (int i = 1; i <= 10; ++i) { 
    int* p = lower_bound(A, A + N, i); 
    cout << "Searching for " << i << ". "; 
    cout << "Result: index = " << p - A << ", "; 
    if (p != A + N) 
     cout << "A[" << p - A << "] == " << *p << endl; 
    else 
     cout << "which is off-the-end." << endl; 
    } 
} 

The output is: 

Searching for 1. Result: index = 0, A[0] == 1 
Searching for 2. Result: index = 1, A[1] == 2 
Searching for 3. Result: index = 2, A[2] == 3 
Searching for 4. Result: index = 5, A[5] == 5 
Searching for 5. Result: index = 5, A[5] == 5 
Searching for 6. Result: index = 6, A[6] == 8 
Searching for 7. Result: index = 6, A[6] == 8 
Searching for 8. Result: index = 6, A[6] == 8 
Searching for 9. Result: index = 7, which is off-the-end. 
Searching for 10. Result: index = 7, which is off-the-end. 

オフライン値は間違って参照することはできませんが、比較の目的で、または挿入ポイントとして使用できます。

どうしてあなたはlower_boundを使用していますか?検索の目的で、必ずfindを使用する必要がありますか? lower_boundを使用している場合は、ファイル名が挿入できる位置が返されますが、見つけようとしているファイル名と同じである必要はありません。言い換えれば、オフザエンドの値と比較するだけでなく、有効なものが返された場合はファイル名と比較する必要があります。

ここにはfindを使用するバージョンがあります。ご覧のとおり、上記の固定バージョンよりも簡単です。

std::vector<std::wstring>::const_iterator target = std::find(expectedResults.begin(), expectedResults.end(), theFileString); 
BOOST_REQUIRE_MESSAGE(target != expectedResults.end(), std::string("The file ") + convertUnicode(theFileString) + " was unexpected."); 
if (target != expectedResults.end()) 
{ 
    expectedResults.erase(target); 
} 
+0

std :: lower_boundのSGIのドキュメントから: 具体的には、注文に違反することなく値を挿入できる最初の位置を返します。 http://www.sgi.com/tech/stl/lower_bound.html 返されるイテレータは、アイテムが見つからない場合でも有効である必要があることを示します。 std :: findは失敗時に終了を返します... lower_boundは信じられません。 –

+0

ああ、あなたが提案したようにコードを編集すると、問題のテストで間違った結果が生成されます。 –

+0

リンク先のページには、オフザエンドの値を返す特定の例があります。 –

0

「現在のコード・ポイントは、すべての 上の方法をジャンプ - あなたが期待するような行で行 に従っていません」

これは通常、あなたがより多くを持っていることを意味1つのスレッドが一度にメソッドに当たる。私は通常、aspxページの1つ以上のオブジェクトが同時にポストバックを引き起こしたときにこれを表示します。

+0

上記のコードにスレッドがありますか? –

+0

私はあなたが最適化されたビルドをデバッグしていると思います - それらをデバッグすることはより難しい傾向があります –

+0

いいえ。ビルドをデバッグします。ユニットテスト用のリリースビルドを構築する理由はありません) –

0

「現在のコード・ポイントは、すべてのメソッドの上にジャンプ - あなたが期待ように、それは行ごとに従わない」

があなたのコンパイラオプションをチェック!あなたはデバッグをして最適化しましたか?

コンパイラを最適化すると、命令の順序を変更してコードを完全に「書き換え」、 ループをアンロールするなどして、デバッガが実行可能命令を元のコード行にマッピングするのが困難になることがあります。

+0

デバッグモードで動作しています:( –