~ubuntu-branches/debian/sid/bitcoin/sid

« back to all changes in this revision

Viewing changes to src/test/bloom_tests.cpp

  • Committer: Package Import Robot
  • Author(s): Scott Howard
  • Date: 2015-07-29 15:45:52 UTC
  • mfrom: (1.1.23)
  • Revision ID: package-import@ubuntu.com-20150729154552-p5t8q38o0ekh1f09
Tags: 0.11.0-1
* New upstream release (Closes: #793622)
  - build on all archs, big endian is now supported
* Updated symbols file
* Added bitcoin-cli.1 manpage from contrib/debian/manpages
* Updated debian/copyright

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
// Copyright (c) 2012-2013 The Bitcoin Core developers
2
 
// Distributed under the MIT/X11 software license, see the accompanying
 
2
// Distributed under the MIT software license, see the accompanying
3
3
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
4
 
5
5
#include "bloom.h"
8
8
#include "clientversion.h"
9
9
#include "key.h"
10
10
#include "merkleblock.h"
 
11
#include "random.h"
11
12
#include "serialize.h"
12
13
#include "streams.h"
13
14
#include "uint256.h"
14
15
#include "util.h"
15
16
#include "utilstrencodings.h"
 
17
#include "test/test_bitcoin.h"
16
18
 
17
19
#include <vector>
18
20
 
20
22
#include <boost/tuple/tuple.hpp>
21
23
 
22
24
using namespace std;
23
 
using namespace boost::tuples;
24
25
 
25
 
BOOST_AUTO_TEST_SUITE(bloom_tests)
 
26
BOOST_FIXTURE_TEST_SUITE(bloom_tests, BasicTestingSetup)
26
27
 
27
28
BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize)
28
29
{
125
126
    spendStream >> spendingTx;
126
127
 
127
128
    CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
128
 
    filter.insert(uint256("0xb4749f017444b051c44dfd2720e88f314ff94f3dd6d56d40ef65854fcd7fff6b"));
 
129
    filter.insert(uint256S("0xb4749f017444b051c44dfd2720e88f314ff94f3dd6d56d40ef65854fcd7fff6b"));
129
130
    BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match tx hash");
130
131
 
131
132
    filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
151
152
    BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match output address");
152
153
 
153
154
    filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
154
 
    filter.insert(COutPoint(uint256("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0));
 
155
    filter.insert(COutPoint(uint256S("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0));
155
156
    BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match COutPoint");
156
157
 
157
158
    filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
158
 
    COutPoint prevOutPoint(uint256("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0);
 
159
    COutPoint prevOutPoint(uint256S("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0);
159
160
    {
160
161
        vector<unsigned char> data(32 + sizeof(unsigned int));
161
162
        memcpy(&data[0], prevOutPoint.hash.begin(), 32);
165
166
    BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match manually serialized COutPoint");
166
167
 
167
168
    filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
168
 
    filter.insert(uint256("00000009e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436"));
 
169
    filter.insert(uint256S("00000009e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436"));
169
170
    BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched random tx hash");
170
171
 
171
172
    filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
173
174
    BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched random address");
174
175
 
175
176
    filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
176
 
    filter.insert(COutPoint(uint256("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 1));
 
177
    filter.insert(COutPoint(uint256S("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 1));
177
178
    BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched COutPoint for an output we didn't care about");
178
179
 
179
180
    filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
180
 
    filter.insert(COutPoint(uint256("0x000000d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0));
 
181
    filter.insert(COutPoint(uint256S("0x000000d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0));
181
182
    BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched COutPoint for an output we didn't care about");
182
183
}
183
184
 
191
192
 
192
193
    CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
193
194
    // Match the last transaction
194
 
    filter.insert(uint256("0x74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20"));
 
195
    filter.insert(uint256S("0x74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20"));
195
196
 
196
197
    CMerkleBlock merkleBlock(block, filter);
197
198
    BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash());
199
200
    BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1);
200
201
    pair<unsigned int, uint256> pair = merkleBlock.vMatchedTxn[0];
201
202
 
202
 
    BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256("0x74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20"));
 
203
    BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0x74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20"));
203
204
    BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 8);
204
205
 
205
206
    vector<uint256> vMatched;
209
210
        BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
210
211
 
211
212
    // Also match the 8th transaction
212
 
    filter.insert(uint256("0xdd1fd2a6fc16404faf339881a90adbde7f4f728691ac62e8f168809cdfae1053"));
 
213
    filter.insert(uint256S("0xdd1fd2a6fc16404faf339881a90adbde7f4f728691ac62e8f168809cdfae1053"));
213
214
    merkleBlock = CMerkleBlock(block, filter);
214
215
    BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash());
215
216
 
217
218
 
218
219
    BOOST_CHECK(merkleBlock.vMatchedTxn[1] == pair);
219
220
 
220
 
    BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256("0xdd1fd2a6fc16404faf339881a90adbde7f4f728691ac62e8f168809cdfae1053"));
 
221
    BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0xdd1fd2a6fc16404faf339881a90adbde7f4f728691ac62e8f168809cdfae1053"));
221
222
    BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 7);
222
223
 
223
224
    BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
236
237
 
237
238
    CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
238
239
    // Match the first transaction
239
 
    filter.insert(uint256("0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70"));
 
240
    filter.insert(uint256S("0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70"));
240
241
 
241
242
    CMerkleBlock merkleBlock(block, filter);
242
243
    BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash());
244
245
    BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1);
245
246
    pair<unsigned int, uint256> pair = merkleBlock.vMatchedTxn[0];
246
247
 
247
 
    BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256("0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70"));
 
248
    BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70"));
248
249
    BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0);
249
250
 
250
251
    vector<uint256> vMatched;
265
266
 
266
267
    BOOST_CHECK(pair == merkleBlock.vMatchedTxn[0]);
267
268
 
268
 
    BOOST_CHECK(merkleBlock.vMatchedTxn[1].second == uint256("0x28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f"));
 
269
    BOOST_CHECK(merkleBlock.vMatchedTxn[1].second == uint256S("0x28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f"));
269
270
    BOOST_CHECK(merkleBlock.vMatchedTxn[1].first == 1);
270
271
 
271
 
    BOOST_CHECK(merkleBlock.vMatchedTxn[2].second == uint256("0x6b0f8a73a56c04b519f1883e8aafda643ba61a30bd1439969df21bea5f4e27e2"));
 
272
    BOOST_CHECK(merkleBlock.vMatchedTxn[2].second == uint256S("0x6b0f8a73a56c04b519f1883e8aafda643ba61a30bd1439969df21bea5f4e27e2"));
272
273
    BOOST_CHECK(merkleBlock.vMatchedTxn[2].first == 2);
273
274
 
274
 
    BOOST_CHECK(merkleBlock.vMatchedTxn[3].second == uint256("0x3c1d7e82342158e4109df2e0b6348b6e84e403d8b4046d7007663ace63cddb23"));
 
275
    BOOST_CHECK(merkleBlock.vMatchedTxn[3].second == uint256S("0x3c1d7e82342158e4109df2e0b6348b6e84e403d8b4046d7007663ace63cddb23"));
275
276
    BOOST_CHECK(merkleBlock.vMatchedTxn[3].first == 3);
276
277
 
277
278
    BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
290
291
 
291
292
    CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_NONE);
292
293
    // Match the first transaction
293
 
    filter.insert(uint256("0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70"));
 
294
    filter.insert(uint256S("0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70"));
294
295
 
295
296
    CMerkleBlock merkleBlock(block, filter);
296
297
    BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash());
298
299
    BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1);
299
300
    pair<unsigned int, uint256> pair = merkleBlock.vMatchedTxn[0];
300
301
 
301
 
    BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256("0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70"));
 
302
    BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70"));
302
303
    BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0);
303
304
 
304
305
    vector<uint256> vMatched;
319
320
 
320
321
    BOOST_CHECK(pair == merkleBlock.vMatchedTxn[0]);
321
322
 
322
 
    BOOST_CHECK(merkleBlock.vMatchedTxn[1].second == uint256("0x28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f"));
 
323
    BOOST_CHECK(merkleBlock.vMatchedTxn[1].second == uint256S("0x28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f"));
323
324
    BOOST_CHECK(merkleBlock.vMatchedTxn[1].first == 1);
324
325
 
325
 
    BOOST_CHECK(merkleBlock.vMatchedTxn[2].second == uint256("0x3c1d7e82342158e4109df2e0b6348b6e84e403d8b4046d7007663ace63cddb23"));
 
326
    BOOST_CHECK(merkleBlock.vMatchedTxn[2].second == uint256S("0x3c1d7e82342158e4109df2e0b6348b6e84e403d8b4046d7007663ace63cddb23"));
326
327
    BOOST_CHECK(merkleBlock.vMatchedTxn[2].first == 3);
327
328
 
328
329
    BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched) == block.hashMerkleRoot);
341
342
 
342
343
    CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
343
344
    // Match the only transaction
344
 
    filter.insert(uint256("0x63194f18be0af63f2c6bc9dc0f777cbefed3d9415c4af83f3ee3a3d669c00cb5"));
 
345
    filter.insert(uint256S("0x63194f18be0af63f2c6bc9dc0f777cbefed3d9415c4af83f3ee3a3d669c00cb5"));
345
346
 
346
347
    CMerkleBlock merkleBlock(block, filter);
347
348
    BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash());
348
349
 
349
350
    BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1);
350
351
 
351
 
    BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256("0x63194f18be0af63f2c6bc9dc0f777cbefed3d9415c4af83f3ee3a3d669c00cb5"));
 
352
    BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0x63194f18be0af63f2c6bc9dc0f777cbefed3d9415c4af83f3ee3a3d669c00cb5"));
352
353
    BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0);
353
354
 
354
355
    vector<uint256> vMatched;
379
380
 
380
381
    CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
381
382
    // Match the last transaction
382
 
    filter.insert(uint256("0x0a2a92f0bda4727d0a13eaddf4dd9ac6b5c61a1429e6b2b818f19b15df0ac154"));
 
383
    filter.insert(uint256S("0x0a2a92f0bda4727d0a13eaddf4dd9ac6b5c61a1429e6b2b818f19b15df0ac154"));
383
384
 
384
385
    CMerkleBlock merkleBlock(block, filter);
385
386
    BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash());
387
388
    BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1);
388
389
    pair<unsigned int, uint256> pair = merkleBlock.vMatchedTxn[0];
389
390
 
390
 
    BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256("0x0a2a92f0bda4727d0a13eaddf4dd9ac6b5c61a1429e6b2b818f19b15df0ac154"));
 
391
    BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0x0a2a92f0bda4727d0a13eaddf4dd9ac6b5c61a1429e6b2b818f19b15df0ac154"));
391
392
    BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 6);
392
393
 
393
394
    vector<uint256> vMatched;
397
398
        BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second);
398
399
 
399
400
    // Also match the 4th transaction
400
 
    filter.insert(uint256("0x02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041"));
 
401
    filter.insert(uint256S("0x02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041"));
401
402
    merkleBlock = CMerkleBlock(block, filter);
402
403
    BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash());
403
404
 
404
405
    BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 2);
405
406
 
406
 
    BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256("0x02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041"));
 
407
    BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0x02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041"));
407
408
    BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 3);
408
409
 
409
410
    BOOST_CHECK(merkleBlock.vMatchedTxn[1] == pair);
432
433
    BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash());
433
434
 
434
435
    // We should match the generation outpoint
435
 
    BOOST_CHECK(filter.contains(COutPoint(uint256("0x147caa76786596590baa4e98f5d9f48b86c7765e489f7a6ff3360fe5c674360b"), 0)));
 
436
    BOOST_CHECK(filter.contains(COutPoint(uint256S("0x147caa76786596590baa4e98f5d9f48b86c7765e489f7a6ff3360fe5c674360b"), 0)));
436
437
    // ... but not the 4th transaction's output (its not pay-2-pubkey)
437
 
    BOOST_CHECK(!filter.contains(COutPoint(uint256("0x02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041"), 0)));
 
438
    BOOST_CHECK(!filter.contains(COutPoint(uint256S("0x02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041"), 0)));
438
439
}
439
440
 
440
441
BOOST_AUTO_TEST_CASE(merkle_block_4_test_update_none)
455
456
    BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash());
456
457
 
457
458
    // We shouldn't match any outpoints (UPDATE_NONE)
458
 
    BOOST_CHECK(!filter.contains(COutPoint(uint256("0x147caa76786596590baa4e98f5d9f48b86c7765e489f7a6ff3360fe5c674360b"), 0)));
459
 
    BOOST_CHECK(!filter.contains(COutPoint(uint256("0x02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041"), 0)));
 
459
    BOOST_CHECK(!filter.contains(COutPoint(uint256S("0x147caa76786596590baa4e98f5d9f48b86c7765e489f7a6ff3360fe5c674360b"), 0)));
 
460
    BOOST_CHECK(!filter.contains(COutPoint(uint256S("0x02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041"), 0)));
 
461
}
 
462
 
 
463
static std::vector<unsigned char> RandomData()
 
464
{
 
465
    uint256 r = GetRandHash();
 
466
    return std::vector<unsigned char>(r.begin(), r.end());
 
467
}
 
468
 
 
469
BOOST_AUTO_TEST_CASE(rolling_bloom)
 
470
{
 
471
    // last-100-entry, 1% false positive:
 
472
    CRollingBloomFilter rb1(100, 0.01, 0);
 
473
 
 
474
    // Overfill:
 
475
    static const int DATASIZE=399;
 
476
    std::vector<unsigned char> data[DATASIZE];
 
477
    for (int i = 0; i < DATASIZE; i++) {
 
478
        data[i] = RandomData();
 
479
        rb1.insert(data[i]);
 
480
    }
 
481
    // Last 100 guaranteed to be remembered:
 
482
    for (int i = 299; i < DATASIZE; i++) {
 
483
        BOOST_CHECK(rb1.contains(data[i]));
 
484
    }
 
485
 
 
486
    // false positive rate is 1%, so we should get about 100 hits if
 
487
    // testing 10,000 random keys. We get worst-case false positive
 
488
    // behavior when the filter is as full as possible, which is
 
489
    // when we've inserted one minus an integer multiple of nElement*2.
 
490
    unsigned int nHits = 0;
 
491
    for (int i = 0; i < 10000; i++) {
 
492
        if (rb1.contains(RandomData()))
 
493
            ++nHits;
 
494
    }
 
495
    // Run test_bitcoin with --log_level=message to see BOOST_TEST_MESSAGEs:
 
496
    BOOST_TEST_MESSAGE("RollingBloomFilter got " << nHits << " false positives (~100 expected)");
 
497
 
 
498
    // Insanely unlikely to get a fp count outside this range:
 
499
    BOOST_CHECK(nHits > 25);
 
500
    BOOST_CHECK(nHits < 175);
 
501
 
 
502
    BOOST_CHECK(rb1.contains(data[DATASIZE-1]));
 
503
    rb1.clear();
 
504
    BOOST_CHECK(!rb1.contains(data[DATASIZE-1]));
 
505
 
 
506
    // Now roll through data, make sure last 100 entries
 
507
    // are always remembered:
 
508
    for (int i = 0; i < DATASIZE; i++) {
 
509
        if (i >= 100)
 
510
            BOOST_CHECK(rb1.contains(data[i-100]));
 
511
        rb1.insert(data[i]);
 
512
    }
 
513
 
 
514
    // Insert 999 more random entries:
 
515
    for (int i = 0; i < 999; i++) {
 
516
        rb1.insert(RandomData());
 
517
    }
 
518
    // Sanity check to make sure the filter isn't just filling up:
 
519
    nHits = 0;
 
520
    for (int i = 0; i < DATASIZE; i++) {
 
521
        if (rb1.contains(data[i]))
 
522
            ++nHits;
 
523
    }
 
524
    // Expect about 5 false positives, more than 100 means
 
525
    // something is definitely broken.
 
526
    BOOST_TEST_MESSAGE("RollingBloomFilter got " << nHits << " false positives (~5 expected)");
 
527
    BOOST_CHECK(nHits < 100);
 
528
 
 
529
    // last-1000-entry, 0.01% false positive:
 
530
    CRollingBloomFilter rb2(1000, 0.001, 0);
 
531
    for (int i = 0; i < DATASIZE; i++) {
 
532
        rb2.insert(data[i]);
 
533
    }
 
534
    // ... room for all of them:
 
535
    for (int i = 0; i < DATASIZE; i++) {
 
536
        BOOST_CHECK(rb2.contains(data[i]));
 
537
    }
460
538
}
461
539
 
462
540
BOOST_AUTO_TEST_SUITE_END()