diff options
author | josh.macdonald <jmacd@users.noreply.github.com> | 2008-06-30 05:15:05 +0000 |
---|---|---|
committer | josh.macdonald <jmacd@users.noreply.github.com> | 2008-06-30 05:15:05 +0000 |
commit | 9e896b470f5a4550a7fbbdc515db08b0249f5950 (patch) | |
tree | 8f2ea4d701f554a578a7d7e441f98e1f77425e9a /xdelta3/testing | |
parent | e127914b71638072798f7c02e93caf9377ba7385 (diff) |
A test is taking shape...
Diffstat (limited to 'xdelta3/testing')
-rwxr-xr-x | xdelta3/testing/Makefile | 4 | ||||
-rw-r--r-- | xdelta3/testing/cmp.h | 37 | ||||
-rw-r--r-- | xdelta3/testing/file.h | 172 | ||||
-rw-r--r-- | xdelta3/testing/modify.h | 23 | ||||
-rw-r--r-- | xdelta3/testing/random.h | 125 | ||||
-rw-r--r-- | xdelta3/testing/regtest.cc | 173 | ||||
-rw-r--r-- | xdelta3/testing/test.h | 59 | ||||
-rw-r--r-- | xdelta3/testing/xdelta3-regtest.cc | 284 |
8 files changed, 591 insertions, 286 deletions
diff --git a/xdelta3/testing/Makefile b/xdelta3/testing/Makefile index a6cd152..50b6e04 100755 --- a/xdelta3/testing/Makefile +++ b/xdelta3/testing/Makefile | |||
@@ -1,13 +1,13 @@ | |||
1 | CFLAGS = -g -Wall -I.. -DXD3_DEBUG=1 -DNDEBUG=0 | 1 | CFLAGS = -g -Wall -I.. -DXD3_DEBUG=1 -DNDEBUG=0 |
2 | 2 | ||
3 | DEPS = ../*.h ../*.c *.cc | 3 | DEPS = ../*.h ../*.c *.cc *.h |
4 | 4 | ||
5 | TARGETS = xdelta3-regtest | 5 | TARGETS = xdelta3-regtest |
6 | 6 | ||
7 | all: $(TARGETS) | 7 | all: $(TARGETS) |
8 | 8 | ||
9 | xdelta3-regtest: $(DEPS) | 9 | xdelta3-regtest: $(DEPS) |
10 | $(CXX) $(CFLAGS) xdelta3-regtest.cc -o xdelta3-regtest | 10 | $(CXX) $(CFLAGS) regtest.cc -o xdelta3-regtest |
11 | 11 | ||
12 | clean: | 12 | clean: |
13 | rm -f *.exe *.stackdump $(TARGETS) | 13 | rm -f *.exe *.stackdump $(TARGETS) |
diff --git a/xdelta3/testing/cmp.h b/xdelta3/testing/cmp.h new file mode 100644 index 0000000..12b499d --- /dev/null +++ b/xdelta3/testing/cmp.h | |||
@@ -0,0 +1,37 @@ | |||
1 | /* -*- Mode: C++ -*- */ | ||
2 | namespace regtest { | ||
3 | |||
4 | inline xoff_t CmpDifferentBytes(const FileSpec &a, const FileSpec &b) { | ||
5 | Block block_a, block_b; | ||
6 | xoff_t total = 0; | ||
7 | FileSpec::iterator a_i(a), b_i(b); | ||
8 | |||
9 | for (; !a_i.Done() && !b_i.Done(); a_i.Next(), b_i.Next()) { | ||
10 | |||
11 | a_i.Get(&block_a); | ||
12 | b_i.Get(&block_b); | ||
13 | |||
14 | size_t i = 0; | ||
15 | size_t m = min(block_a.Size(), block_b.Size()); | ||
16 | |||
17 | for (; i < m; i++) { | ||
18 | if (block_a[i] != block_b[i]) { | ||
19 | total++; | ||
20 | } | ||
21 | } | ||
22 | |||
23 | total += block_a.Size() - i; | ||
24 | total += block_b.Size() - i; | ||
25 | } | ||
26 | |||
27 | for (; !a_i.Done(); a_i.Next()) { | ||
28 | total += a_i.BytesOnBlock(); | ||
29 | } | ||
30 | for (; !b_i.Done(); b_i.Next()) { | ||
31 | total += b_i.BytesOnBlock(); | ||
32 | } | ||
33 | |||
34 | return total; | ||
35 | } | ||
36 | |||
37 | } // namespace regtest | ||
diff --git a/xdelta3/testing/file.h b/xdelta3/testing/file.h new file mode 100644 index 0000000..4dbb07d --- /dev/null +++ b/xdelta3/testing/file.h | |||
@@ -0,0 +1,172 @@ | |||
1 | /* -*- Mode: C++ -*- */ | ||
2 | namespace regtest { | ||
3 | |||
4 | class Segment { | ||
5 | public: | ||
6 | Segment(uint32_t seed, size_t length) | ||
7 | : seed(seed), | ||
8 | length(length), | ||
9 | seed_offset(0) { } | ||
10 | |||
11 | uint32_t seed; // Seed used for generating byte sequence | ||
12 | size_t length; // Length of this segment | ||
13 | size_t seed_offset; // Seed positions the sequence this many bytes | ||
14 | // before its beginning. | ||
15 | }; | ||
16 | |||
17 | typedef map<xoff_t, Segment> SegmentMap; | ||
18 | |||
19 | class Block; | ||
20 | class BlockIterator; | ||
21 | |||
22 | class FileSpec { | ||
23 | public: | ||
24 | FileSpec(MTRandom *rand) | ||
25 | : rand_(rand) { | ||
26 | } | ||
27 | |||
28 | // Generates a file with a known size | ||
29 | void GenerateFixedSize(xoff_t size) { | ||
30 | Reset(); | ||
31 | |||
32 | for (xoff_t p = 0; p < size; ) { | ||
33 | xoff_t t = min(Constants::BLOCK_SIZE, size - p); | ||
34 | table_.insert(make_pair(p, Segment(rand_->Rand32(), t))); | ||
35 | p += t; | ||
36 | } | ||
37 | } | ||
38 | |||
39 | // Generates a file with exponential-random distributed size | ||
40 | void GenerateRandomSize(xoff_t mean) { | ||
41 | GenerateFixedSize(rand_->ExpRand(mean)); | ||
42 | } | ||
43 | |||
44 | // Returns the size of the file | ||
45 | xoff_t Size() const { | ||
46 | if (table_.empty()) { | ||
47 | return 0; | ||
48 | } | ||
49 | SegmentMap::const_iterator i = --table_.end(); | ||
50 | return i->first + i->second.length; | ||
51 | } | ||
52 | |||
53 | // Returns the number of blocks | ||
54 | xoff_t Blocks() const { | ||
55 | if (table_.empty()) { | ||
56 | return 0; | ||
57 | } | ||
58 | return ((Size() - 1) / Constants::BLOCK_SIZE) + 1; | ||
59 | } | ||
60 | |||
61 | // Returns the number of segments | ||
62 | xoff_t Segments() const { | ||
63 | return table_.size(); | ||
64 | } | ||
65 | |||
66 | // Create a mutation according to "what". | ||
67 | template <typename T> | ||
68 | void ModifyTo(FileSpec *modify) const { | ||
69 | modify->table_ = table_; | ||
70 | T::Mutate(&modify->table_, rand_); | ||
71 | } | ||
72 | |||
73 | void Reset() { | ||
74 | table_.clear(); | ||
75 | } | ||
76 | |||
77 | typedef BlockIterator iterator; | ||
78 | |||
79 | private: | ||
80 | friend class BlockIterator; | ||
81 | |||
82 | MTRandom *rand_; | ||
83 | SegmentMap table_; | ||
84 | }; | ||
85 | |||
86 | class Block { | ||
87 | public: | ||
88 | Block() | ||
89 | : data_(new uint8_t[Constants::BLOCK_SIZE]) { } | ||
90 | ~Block() { | ||
91 | delete [] data_; | ||
92 | } | ||
93 | |||
94 | size_t Size() const { | ||
95 | return size_; | ||
96 | } | ||
97 | uint8_t operator[](size_t i) const { | ||
98 | CHECK_LT(i, Constants::BLOCK_SIZE); | ||
99 | return data_[i]; | ||
100 | } | ||
101 | |||
102 | private: | ||
103 | friend class BlockIterator; | ||
104 | |||
105 | size_t size_; | ||
106 | uint8_t *data_; | ||
107 | }; | ||
108 | |||
109 | class BlockIterator { | ||
110 | public: | ||
111 | BlockIterator(const FileSpec& spec) | ||
112 | : spec_(spec), | ||
113 | blkno_(0) { } | ||
114 | |||
115 | bool Done() const { | ||
116 | return blkno_ >= spec_.Blocks(); | ||
117 | } | ||
118 | |||
119 | void Next() { | ||
120 | blkno_++; | ||
121 | } | ||
122 | |||
123 | void Get(Block *block) const; | ||
124 | |||
125 | size_t BytesOnBlock() const { | ||
126 | // Blocks() is unsigned, don't subtract | ||
127 | if (blkno_ + 1 < spec_.Blocks()) { | ||
128 | return Constants::BLOCK_SIZE; | ||
129 | } | ||
130 | return spec_.Size() % Constants::BLOCK_SIZE; | ||
131 | } | ||
132 | |||
133 | private: | ||
134 | const FileSpec& spec_; | ||
135 | xoff_t blkno_; | ||
136 | }; | ||
137 | |||
138 | inline void BlockIterator::Get(Block *block) const { | ||
139 | xoff_t offset = blkno_ * Constants::BLOCK_SIZE; | ||
140 | const SegmentMap &table = spec_.table_; | ||
141 | size_t got = 0; | ||
142 | block->size_ = BytesOnBlock(); | ||
143 | |||
144 | SegmentMap::const_iterator pos = table.upper_bound(offset); | ||
145 | --pos; | ||
146 | |||
147 | while (got < block->size_) { | ||
148 | CHECK(pos != table.end()); | ||
149 | CHECK_GE(offset, pos->first); | ||
150 | |||
151 | // The position of this segment may start before this block starts, | ||
152 | // and then the position of the data may be offset from the seeding | ||
153 | // position. | ||
154 | size_t seg_offset = offset - pos->first; | ||
155 | xoff_t skip = seg_offset + pos->second.seed_offset; | ||
156 | MTRandom gen(pos->second.seed); | ||
157 | while (skip--) { | ||
158 | gen.Rand32(); | ||
159 | } | ||
160 | |||
161 | for (size_t i = seg_offset; i < pos->second.length; i++) { | ||
162 | CHECK_LT(got, Constants::BLOCK_SIZE); | ||
163 | block->data_[got++] = gen.Rand32(); | ||
164 | } | ||
165 | |||
166 | offset += (pos->second.length - seg_offset); | ||
167 | ++pos; | ||
168 | } | ||
169 | } | ||
170 | |||
171 | } // namespace regtest | ||
172 | |||
diff --git a/xdelta3/testing/modify.h b/xdelta3/testing/modify.h new file mode 100644 index 0000000..8d6b480 --- /dev/null +++ b/xdelta3/testing/modify.h | |||
@@ -0,0 +1,23 @@ | |||
1 | /* -*- Mode: C++ -*- */ | ||
2 | namespace regtest { | ||
3 | |||
4 | class Modify1stByte { | ||
5 | public: | ||
6 | static void Mutate(SegmentMap *table, MTRandom *rand) { | ||
7 | CHECK(!table->empty()); | ||
8 | |||
9 | SegmentMap::iterator i1 = table->begin(); | ||
10 | CHECK_EQ(0, i1->first); | ||
11 | |||
12 | if (i1->second.length == 1) { | ||
13 | i1->second.seed = rand->Rand32(); | ||
14 | } else { | ||
15 | i1->second.seed_offset += 1; | ||
16 | i1->second.length -= 1; | ||
17 | table->insert(make_pair(1, i1->second)); | ||
18 | i1->second = Segment(rand->Rand32(), 1); | ||
19 | } | ||
20 | } | ||
21 | }; | ||
22 | |||
23 | } // namespace regtest | ||
diff --git a/xdelta3/testing/random.h b/xdelta3/testing/random.h new file mode 100644 index 0000000..6648edb --- /dev/null +++ b/xdelta3/testing/random.h | |||
@@ -0,0 +1,125 @@ | |||
1 | /* -*- Mode: C++ -*- */ | ||
2 | /* This is public-domain Mersenne Twister code, | ||
3 | * attributed to Michael Brundage. Thanks! | ||
4 | * http://www.qbrundage.com/michaelb/pubs/essays/random_number_generation.html | ||
5 | */ | ||
6 | #include <math.h> | ||
7 | |||
8 | namespace regtest { | ||
9 | |||
10 | class MTRandom { | ||
11 | public: | ||
12 | static const uint32_t TEST_SEED1 = 0x1975; | ||
13 | |||
14 | static const int MT_LEN = 624; | ||
15 | static const int MT_IA = 397; | ||
16 | static const int MT_IB = (MT_LEN - MT_IA); | ||
17 | static const uint32_t UPPER_MASK = 0x80000000; | ||
18 | static const uint32_t LOWER_MASK = 0x7FFFFFFF; | ||
19 | static const uint32_t MATRIX_A = 0x9908B0DF; | ||
20 | |||
21 | MTRandom() { | ||
22 | Init(TEST_SEED1); | ||
23 | } | ||
24 | |||
25 | MTRandom(uint32_t seed) { | ||
26 | Init(seed); | ||
27 | } | ||
28 | |||
29 | uint32_t TWIST(int i, int j) { | ||
30 | return (mt_buffer_[i] & UPPER_MASK) | (mt_buffer_[j] & LOWER_MASK); | ||
31 | } | ||
32 | |||
33 | uint32_t MAGIC(uint32_t s) { | ||
34 | return (s & 1) * MATRIX_A; | ||
35 | } | ||
36 | |||
37 | uint32_t Rand32 () { | ||
38 | int idx = mt_index_; | ||
39 | uint32_t s; | ||
40 | int i; | ||
41 | |||
42 | if (idx == MT_LEN * sizeof(uint32_t)) { | ||
43 | idx = 0; | ||
44 | i = 0; | ||
45 | for (; i < MT_IB; i++) { | ||
46 | s = TWIST(i, i+1); | ||
47 | mt_buffer_[i] = mt_buffer_[i + MT_IA] ^ (s >> 1) ^ MAGIC(s); | ||
48 | } | ||
49 | for (; i < MT_LEN-1; i++) { | ||
50 | s = TWIST(i, i+1); | ||
51 | mt_buffer_[i] = mt_buffer_[i - MT_IB] ^ (s >> 1) ^ MAGIC(s); | ||
52 | } | ||
53 | |||
54 | s = TWIST(MT_LEN-1, 0); | ||
55 | mt_buffer_[MT_LEN-1] = mt_buffer_[MT_IA-1] ^ (s >> 1) ^ MAGIC(s); | ||
56 | } | ||
57 | mt_index_ = idx + sizeof(uint32_t); | ||
58 | |||
59 | // Original code had an unaligned access, make it portable. | ||
60 | // return *(uint32_t *)((unsigned char *)b + idx); | ||
61 | uint32_t r; | ||
62 | memcpy(&r, ((unsigned char *)mt_buffer_ + idx), sizeof(uint32_t)); | ||
63 | return r; | ||
64 | } | ||
65 | |||
66 | uint32_t ExpRand32(uint32_t mean) { | ||
67 | double mean_d = mean; | ||
68 | double erand = log (1.0 / (Rand32() / (double)UINT32_MAX)); | ||
69 | uint32_t x = (uint32_t) (mean_d * erand + 0.5); | ||
70 | return x; | ||
71 | } | ||
72 | |||
73 | uint64_t Rand64() { | ||
74 | return ((uint64_t)Rand32() << 32) | Rand32(); | ||
75 | } | ||
76 | |||
77 | uint64_t ExpRand64(uint64_t mean) { | ||
78 | double mean_d = mean; | ||
79 | double erand = log (1.0 / (Rand64() / (double)UINT32_MAX)); | ||
80 | uint64_t x = (uint64_t) (mean_d * erand + 0.5); | ||
81 | return x; | ||
82 | } | ||
83 | |||
84 | template <typename T> | ||
85 | T Rand() { | ||
86 | switch (sizeof(T)) { | ||
87 | case sizeof(uint32_t): | ||
88 | return Rand32(); | ||
89 | case sizeof(uint64_t): | ||
90 | return Rand64(); | ||
91 | default: | ||
92 | cerr << "Invalid sizeof T" << endl; | ||
93 | abort(); | ||
94 | } | ||
95 | } | ||
96 | |||
97 | template <typename T> | ||
98 | T ExpRand(T mean) { | ||
99 | switch (sizeof(T)) { | ||
100 | case sizeof(uint32_t): | ||
101 | return ExpRand32(mean); | ||
102 | case sizeof(uint64_t): | ||
103 | return ExpRand64(mean); | ||
104 | default: | ||
105 | cerr << "Invalid sizeof T" << endl; | ||
106 | abort(); | ||
107 | } | ||
108 | } | ||
109 | |||
110 | private: | ||
111 | void Init(uint32_t seed) { | ||
112 | int i; | ||
113 | srand (seed); | ||
114 | for (i = 0; i < MT_LEN; i++) | ||
115 | { | ||
116 | mt_buffer_[i] = rand (); | ||
117 | } | ||
118 | mt_index_ = 0; | ||
119 | } | ||
120 | |||
121 | int mt_index_; | ||
122 | uint32_t mt_buffer_[MT_LEN]; | ||
123 | }; | ||
124 | |||
125 | } // namespace regtest | ||
diff --git a/xdelta3/testing/regtest.cc b/xdelta3/testing/regtest.cc new file mode 100644 index 0000000..489b58a --- /dev/null +++ b/xdelta3/testing/regtest.cc | |||
@@ -0,0 +1,173 @@ | |||
1 | /* -*- Mode: C++ -*- */ | ||
2 | #include "test.h" | ||
3 | |||
4 | // Declare constants (needed for reference-values, etc). | ||
5 | const xoff_t Constants::BLOCK_SIZE; | ||
6 | |||
7 | void TestRandomNumbers() { | ||
8 | MTRandom rand; | ||
9 | int rounds = 1<<20; | ||
10 | uint64_t usum = 0; | ||
11 | uint64_t esum = 0; | ||
12 | |||
13 | for (int i = 0; i < rounds; i++) { | ||
14 | usum += rand.Rand32(); | ||
15 | esum += rand.ExpRand32(1024); | ||
16 | } | ||
17 | |||
18 | double allowed_error = 0.001; | ||
19 | |||
20 | uint32_t umean = usum / rounds; | ||
21 | uint32_t emean = esum / rounds; | ||
22 | |||
23 | uint32_t uexpect = UINT32_MAX / 2; | ||
24 | uint32_t eexpect = 1024; | ||
25 | |||
26 | if (umean < uexpect * (1.0 - allowed_error) || | ||
27 | umean > uexpect * (1.0 + allowed_error)) { | ||
28 | cerr << "uniform mean error: " << umean << " != " << uexpect << endl; | ||
29 | abort(); | ||
30 | } | ||
31 | |||
32 | if (emean < eexpect * (1.0 - allowed_error) || | ||
33 | emean > eexpect * (1.0 + allowed_error)) { | ||
34 | cerr << "exponential mean error: " << emean << " != " << eexpect << endl; | ||
35 | abort(); | ||
36 | } | ||
37 | } | ||
38 | |||
39 | void TestRandomFile() { | ||
40 | MTRandom rand1; | ||
41 | FileSpec spec1(&rand1); | ||
42 | |||
43 | spec1.GenerateFixedSize(0); | ||
44 | CHECK_EQ(0, spec1.Size()); | ||
45 | CHECK_EQ(0, spec1.Segments()); | ||
46 | CHECK_EQ(0, spec1.Blocks()); | ||
47 | |||
48 | spec1.GenerateFixedSize(1); | ||
49 | CHECK_EQ(1, spec1.Size()); | ||
50 | CHECK_EQ(1, spec1.Segments()); | ||
51 | CHECK_EQ(1, spec1.Blocks()); | ||
52 | |||
53 | spec1.GenerateFixedSize(Constants::BLOCK_SIZE); | ||
54 | CHECK_EQ(Constants::BLOCK_SIZE, spec1.Size()); | ||
55 | CHECK_EQ(1, spec1.Segments()); | ||
56 | CHECK_EQ(1, spec1.Blocks()); | ||
57 | |||
58 | spec1.GenerateFixedSize(Constants::BLOCK_SIZE + 1); | ||
59 | CHECK_EQ(Constants::BLOCK_SIZE + 1, spec1.Size()); | ||
60 | CHECK_EQ(2, spec1.Segments()); | ||
61 | CHECK_EQ(2, spec1.Blocks()); | ||
62 | |||
63 | spec1.GenerateFixedSize(Constants::BLOCK_SIZE * 2); | ||
64 | CHECK_EQ(Constants::BLOCK_SIZE * 2, spec1.Size()); | ||
65 | CHECK_EQ(2, spec1.Segments()); | ||
66 | CHECK_EQ(2, spec1.Blocks()); | ||
67 | } | ||
68 | |||
69 | void TestFirstByte() { | ||
70 | MTRandom rand; | ||
71 | FileSpec spec0(&rand); | ||
72 | FileSpec spec1(&rand); | ||
73 | spec0.GenerateFixedSize(0); | ||
74 | spec1.GenerateFixedSize(1); | ||
75 | CHECK_EQ(0, CmpDifferentBytes(spec0, spec0)); | ||
76 | CHECK_EQ(0, CmpDifferentBytes(spec1, spec1)); | ||
77 | CHECK_EQ(1, CmpDifferentBytes(spec0, spec1)); | ||
78 | CHECK_EQ(1, CmpDifferentBytes(spec1, spec0)); | ||
79 | |||
80 | spec0.GenerateFixedSize(1); | ||
81 | spec0.ModifyTo<Modify1stByte>(&spec1); | ||
82 | CHECK_EQ(1, CmpDifferentBytes(spec0, spec1)); | ||
83 | |||
84 | spec0.GenerateFixedSize(Constants::BLOCK_SIZE + 1); | ||
85 | spec0.ModifyTo<Modify1stByte>(&spec1); | ||
86 | CHECK_EQ(1, CmpDifferentBytes(spec0, spec1)); | ||
87 | } | ||
88 | |||
89 | int main(int argc, char **argv) { | ||
90 | #define TEST(x) cerr << #x << "..." << endl; x() | ||
91 | TEST(TestRandomNumbers); | ||
92 | TEST(TestRandomFile); | ||
93 | TEST(TestFirstByte); | ||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | #if 0 | ||
98 | static const random_parameters test_parameters[] = { | ||
99 | { 16384, 4096, 16, 0 }, | ||
100 | { 16384, 4096, 0, 16 }, | ||
101 | { 16384, 4096, 16, 16 }, | ||
102 | { 16384, 4096, 128, 128 }, | ||
103 | }; | ||
104 | |||
105 | int | ||
106 | test_merge_chain (random_file_spec *specs, int number) | ||
107 | { | ||
108 | /* "number" is from 1 (a single delta) between specs[0] and | ||
109 | * specs[1], to N, an (N-1) chain from specs[0] to specs[N]. */ | ||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | static int | ||
114 | test_merge_command () | ||
115 | { | ||
116 | /* Repeat random-input testing for a number of iterations. | ||
117 | * Test 2, 3, and 4-file scenarios (i.e., 1, 2, and 3-delta merges). */ | ||
118 | int ret; | ||
119 | int iter = 0, param = 0; | ||
120 | random_file_spec spec[4]; | ||
121 | |||
122 | memset (spec, 0, sizeof (spec)); | ||
123 | |||
124 | /* Repeat this loop for TESTS_PER_PARAMETER * #parameters * 2. The | ||
125 | * first #parameters repeats are for the provided values, the second | ||
126 | * set of repeats use random parameters. */ | ||
127 | for (; param < (2 * SIZEOF_ARRAY(test_parameters)); iter++) | ||
128 | { | ||
129 | if (iter % TESTS_PER_PARAMETER == 0) | ||
130 | { | ||
131 | if (param < SIZEOF_ARRAY(test_parameters)) | ||
132 | { | ||
133 | set_test_parameters (&test_parameters[param]); | ||
134 | } | ||
135 | else | ||
136 | { | ||
137 | set_random_parameters (); | ||
138 | } | ||
139 | |||
140 | param++; | ||
141 | |||
142 | if ((ret = random_file_spec_generate (&spec[0]))) { return ret; } | ||
143 | if ((ret = random_file_spec_write (&spec[0]))) { return ret; } | ||
144 | |||
145 | if ((ret = random_file_spec_mutate (&spec[0], &spec[1]))) { return ret; } | ||
146 | if ((ret = random_file_spec_write (&spec[1]))) { return ret; } | ||
147 | if ((ret = random_file_spec_delta (&spec[0], &spec[1]))) { return ret; } | ||
148 | |||
149 | if ((ret = random_file_spec_mutate (&spec[1], &spec[2]))) { return ret; } | ||
150 | if ((ret = random_file_spec_write (&spec[2]))) { return ret; } | ||
151 | if ((ret = random_file_spec_delta (&spec[1], &spec[2]))) { return ret; } | ||
152 | } | ||
153 | |||
154 | /* Each iteration creates a new mutation. */ | ||
155 | if ((ret = random_file_spec_mutate (&spec[2], &spec[3]))) { return ret; } | ||
156 | if ((ret = random_file_spec_write (&spec[3]))) { return ret; } | ||
157 | if ((ret = random_file_spec_delta (&spec[2], &spec[3]))) { return ret; } | ||
158 | |||
159 | /* Test 1, 2, and 3 */ | ||
160 | if ((ret = test_merge_chain (spec, 1))) { return ret; } | ||
161 | if ((ret = test_merge_chain (spec, 2))) { return ret; } | ||
162 | if ((ret = test_merge_chain (spec, 3))) { return ret; } | ||
163 | |||
164 | /* Clear 1st input, shift inputs */ | ||
165 | random_file_spec_clear (&spec[0]); | ||
166 | random_file_spec_swap (&spec[0], &spec[1]); | ||
167 | random_file_spec_swap (&spec[1], &spec[2]); | ||
168 | random_file_spec_swap (&spec[2], &spec[3]); | ||
169 | } | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | #endif | ||
diff --git a/xdelta3/testing/test.h b/xdelta3/testing/test.h new file mode 100644 index 0000000..dcec6d9 --- /dev/null +++ b/xdelta3/testing/test.h | |||
@@ -0,0 +1,59 @@ | |||
1 | /* -*- Mode: C++ -*- */ | ||
2 | |||
3 | extern "C" { | ||
4 | #define NOT_MAIN 1 | ||
5 | #define REGRESSION_TEST 0 | ||
6 | #include "../xdelta3.c" | ||
7 | } | ||
8 | |||
9 | #define CHECK_EQ(x,y) CHECK_OP(x,y,==) | ||
10 | #define CHECK_LT(x,y) CHECK_OP(x,y,<) | ||
11 | #define CHECK_GT(x,y) CHECK_OP(x,y,>) | ||
12 | #define CHECK_LE(x,y) CHECK_OP(x,y,<=) | ||
13 | #define CHECK_GE(x,y) CHECK_OP(x,y,>=) | ||
14 | |||
15 | #define CHECK_OP(x,y,OP) \ | ||
16 | do {if (!((x) OP (y))) { \ | ||
17 | cerr << "Check failed: " << #x " " #OP " " #y << endl; \ | ||
18 | cerr << "Expected: " << x << endl; \ | ||
19 | cerr << "Actual: " << y << endl; \ | ||
20 | abort(); \ | ||
21 | } } while (false) | ||
22 | |||
23 | #define CHECK(x) \ | ||
24 | do {if (!(x)) { \ | ||
25 | cerr << "Check failed: " << #x << endl; \ | ||
26 | abort(); \ | ||
27 | } } while (false) | ||
28 | |||
29 | #include <iostream> | ||
30 | using std::cerr; | ||
31 | using std::endl; | ||
32 | |||
33 | #include <map> | ||
34 | using std::map; | ||
35 | using std::pair; | ||
36 | |||
37 | template <typename T, typename U> | ||
38 | pair<T, U> make_pair(const T& t, const U& u) { | ||
39 | return pair<T, U>(t, u); | ||
40 | } | ||
41 | |||
42 | class Constants { | ||
43 | public: | ||
44 | static const xoff_t BLOCK_SIZE = 1 << 14; | ||
45 | }; | ||
46 | |||
47 | using std::min; | ||
48 | |||
49 | #include "random.h" | ||
50 | using regtest::MTRandom; | ||
51 | |||
52 | #include "file.h" | ||
53 | using regtest::FileSpec; | ||
54 | |||
55 | #include "modify.h" | ||
56 | using regtest::Modify1stByte; | ||
57 | |||
58 | #include "cmp.h" | ||
59 | using regtest::CmpDifferentBytes; | ||
diff --git a/xdelta3/testing/xdelta3-regtest.cc b/xdelta3/testing/xdelta3-regtest.cc deleted file mode 100644 index a43ed92..0000000 --- a/xdelta3/testing/xdelta3-regtest.cc +++ /dev/null | |||
@@ -1,284 +0,0 @@ | |||
1 | /* xdelta 3 - delta compression tools and library | ||
2 | * Copyright (C) 2001, 2003, 2004, 2005, 2006, 2007, 2008. Joshua P. MacDonald | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | // This file started because I wanted to write a test in C++ rather than C. | ||
20 | |||
21 | extern "C" { | ||
22 | #define NOT_MAIN 1 | ||
23 | #define REGRESSION_TEST 1 | ||
24 | #include "../xdelta3.c" | ||
25 | } | ||
26 | |||
27 | namespace { | ||
28 | |||
29 | const int TEST_SEED1 = 0x1970; | ||
30 | |||
31 | class RandomFileSpec { | ||
32 | public: | ||
33 | RandomFileSpec() | ||
34 | : size_(0), | ||
35 | seed_(0), | ||
36 | filedata_(NULL), | ||
37 | filename_(NULL), | ||
38 | deltafile_(NULL) { | ||
39 | main_file_init(&file_); | ||
40 | mt_init(&mt_, TEST_SEED1); | ||
41 | } | ||
42 | int size_; | ||
43 | int seed_; | ||
44 | uint8_t *filedata_; | ||
45 | char *filename_; | ||
46 | char *deltafile_; | ||
47 | main_file file_; | ||
48 | mtrand mt_; | ||
49 | }; | ||
50 | |||
51 | } // namespace | ||
52 | |||
53 | int main(int argc, char **argv) { | ||
54 | RandomFileSpec spec1; | ||
55 | |||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | |||
60 | #if 0 | ||
61 | static const int TESTS_PER_PARAMETER = 100; | ||
62 | |||
63 | struct random_file_spec_ { | ||
64 | int size; | ||
65 | int seed; | ||
66 | main_file file; | ||
67 | uint8_t *tmp_data; | ||
68 | char *tmp_copy; | ||
69 | char *tmp_delta; | ||
70 | mtrand mt; | ||
71 | }; | ||
72 | |||
73 | struct random_parameters_ { | ||
74 | int file_size; | ||
75 | int window_size; | ||
76 | int add_size; | ||
77 | int del_size; | ||
78 | }; | ||
79 | |||
80 | typedef struct random_file_spec_ random_file_spec; | ||
81 | typedef struct random_parameters_ random_parameters; | ||
82 | |||
83 | static const random_parameters test_parameters[] = { | ||
84 | { 16384, 4096, 16, 0 }, | ||
85 | { 16384, 4096, 0, 16 }, | ||
86 | { 16384, 4096, 16, 16 }, | ||
87 | { 16384, 4096, 128, 128 }, | ||
88 | }; | ||
89 | |||
90 | static random_parameters current_parameters; | ||
91 | static int test2_malloc_count; | ||
92 | |||
93 | void | ||
94 | set_test_parameters (const random_parameters *params) | ||
95 | { | ||
96 | current_parameters = *params; | ||
97 | } | ||
98 | |||
99 | void | ||
100 | set_random_parameters () | ||
101 | { | ||
102 | // TODO(jmacd) | ||
103 | current_parameters = test_parameters[0]; | ||
104 | } | ||
105 | |||
106 | void* | ||
107 | test2_malloc (int size) | ||
108 | { | ||
109 | test2_malloc_count++; | ||
110 | return malloc(size); | ||
111 | } | ||
112 | |||
113 | void | ||
114 | test2_free (void *ptr) | ||
115 | { | ||
116 | test2_malloc_count--; | ||
117 | free (ptr); | ||
118 | XD3_ASSERT (test2_malloc_count >= 0); | ||
119 | } | ||
120 | |||
121 | void | ||
122 | random_file_spec_clear (random_file_spec *spec) | ||
123 | { | ||
124 | if (spec->tmp_copy) | ||
125 | { | ||
126 | unlink (spec->tmp_copy); /* TODO(jmacd): make portable */ | ||
127 | test2_free (spec->tmp_copy); | ||
128 | spec->tmp_copy = NULL; | ||
129 | } | ||
130 | |||
131 | if (spec->tmp_delta) | ||
132 | { | ||
133 | unlink (spec->tmp_delta); | ||
134 | test2_free (spec->tmp_delta); | ||
135 | spec->tmp_delta = NULL; | ||
136 | } | ||
137 | |||
138 | if (spec->tmp_data) | ||
139 | { | ||
140 | test2_free (spec->tmp_data); | ||
141 | spec->tmp_data = NULL; | ||
142 | } | ||
143 | } | ||
144 | |||
145 | void | ||
146 | random_file_spec_swap (random_file_spec *a, | ||
147 | random_file_spec *b) | ||
148 | { | ||
149 | random_file_spec t = *a; | ||
150 | *a = *b; | ||
151 | *b = t; | ||
152 | } | ||
153 | |||
154 | int | ||
155 | random_file_spec_generate (random_file_spec *spec) | ||
156 | { | ||
157 | int i; | ||
158 | spec->seed = mt_random (&static_mtrand); | ||
159 | mt_init (&spec->mt, spec->seed); | ||
160 | main_file_init (&spec->file); | ||
161 | |||
162 | test_setup(); | ||
163 | spec->tmp_copy = test2_malloc(strlen(TEST_TARGET_FILE) + 1); | ||
164 | strcpy (spec->tmp_copy, TEST_TARGET_FILE); | ||
165 | |||
166 | spec->size = current_parameters.file_size; | ||
167 | spec->tmp_data = (uint8_t*)test2_malloc(spec->size); | ||
168 | |||
169 | for (i = 0; i < spec->size; i++) | ||
170 | { | ||
171 | spec->tmp_data[i] = mt_random(&spec->mt); | ||
172 | } | ||
173 | |||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | int | ||
178 | random_file_spec_write (random_file_spec *spec) | ||
179 | { | ||
180 | int ret; | ||
181 | if ((ret = main_file_open (&spec->file, spec->tmp_copy, XO_WRITE)) || | ||
182 | (ret = main_file_write (&spec->file, spec->tmp_data, spec->size, | ||
183 | "write failed")) || | ||
184 | (ret = main_file_close (&spec->file))) | ||
185 | { | ||
186 | return ret; | ||
187 | } | ||
188 | |||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | int | ||
193 | random_file_spec_mutate (random_file_spec *from, random_file_spec *to) | ||
194 | { | ||
195 | to->seed = mt_random (&static_mtrand); | ||
196 | mt_init (&to->mt, to->seed); | ||
197 | main_file_init (&spec->file); | ||
198 | |||
199 | test_setup(); | ||
200 | spec->tmp_copy = test2_malloc(strlen(TEST_TARGET_FILE) + 1); | ||
201 | strcpy (spec->tmp_copy, TEST_TARGET_FILE); | ||
202 | |||
203 | spec->size = current_parameters.file_size; | ||
204 | spec->tmp_data = (uint8_t*)test2_malloc(spec->size); | ||
205 | |||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | int | ||
211 | random_file_spec_delta (random_file_spec *from, random_file_spec *to) | ||
212 | { | ||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | int | ||
217 | test_merge_chain (random_file_spec *specs, int number) | ||
218 | { | ||
219 | /* "number" is from 1 (a single delta) between specs[0] and | ||
220 | * specs[1], to N, an (N-1) chain from specs[0] to specs[N]. */ | ||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | static int | ||
225 | test_merge_command () | ||
226 | { | ||
227 | /* Repeat random-input testing for a number of iterations. | ||
228 | * Test 2, 3, and 4-file scenarios (i.e., 1, 2, and 3-delta merges). */ | ||
229 | int ret; | ||
230 | int iter = 0, param = 0; | ||
231 | random_file_spec spec[4]; | ||
232 | |||
233 | memset (spec, 0, sizeof (spec)); | ||
234 | |||
235 | /* Repeat this loop for TESTS_PER_PARAMETER * #parameters * 2. The | ||
236 | * first #parameters repeats are for the provided values, the second | ||
237 | * set of repeats use random parameters. */ | ||
238 | for (; param < (2 * SIZEOF_ARRAY(test_parameters)); iter++) | ||
239 | { | ||
240 | if (iter % TESTS_PER_PARAMETER == 0) | ||
241 | { | ||
242 | if (param < SIZEOF_ARRAY(test_parameters)) | ||
243 | { | ||
244 | set_test_parameters (&test_parameters[param]); | ||
245 | } | ||
246 | else | ||
247 | { | ||
248 | set_random_parameters (); | ||
249 | } | ||
250 | |||
251 | param++; | ||
252 | |||
253 | if ((ret = random_file_spec_generate (&spec[0]))) { return ret; } | ||
254 | if ((ret = random_file_spec_write (&spec[0]))) { return ret; } | ||
255 | |||
256 | if ((ret = random_file_spec_mutate (&spec[0], &spec[1]))) { return ret; } | ||
257 | if ((ret = random_file_spec_write (&spec[1]))) { return ret; } | ||
258 | if ((ret = random_file_spec_delta (&spec[0], &spec[1]))) { return ret; } | ||
259 | |||
260 | if ((ret = random_file_spec_mutate (&spec[1], &spec[2]))) { return ret; } | ||
261 | if ((ret = random_file_spec_write (&spec[2]))) { return ret; } | ||
262 | if ((ret = random_file_spec_delta (&spec[1], &spec[2]))) { return ret; } | ||
263 | } | ||
264 | |||
265 | /* Each iteration creates a new mutation. */ | ||
266 | if ((ret = random_file_spec_mutate (&spec[2], &spec[3]))) { return ret; } | ||
267 | if ((ret = random_file_spec_write (&spec[3]))) { return ret; } | ||
268 | if ((ret = random_file_spec_delta (&spec[2], &spec[3]))) { return ret; } | ||
269 | |||
270 | /* Test 1, 2, and 3 */ | ||
271 | if ((ret = test_merge_chain (spec, 1))) { return ret; } | ||
272 | if ((ret = test_merge_chain (spec, 2))) { return ret; } | ||
273 | if ((ret = test_merge_chain (spec, 3))) { return ret; } | ||
274 | |||
275 | /* Clear 1st input, shift inputs */ | ||
276 | random_file_spec_clear (&spec[0]); | ||
277 | random_file_spec_swap (&spec[0], &spec[1]); | ||
278 | random_file_spec_swap (&spec[1], &spec[2]); | ||
279 | random_file_spec_swap (&spec[2], &spec[3]); | ||
280 | } | ||
281 | |||
282 | return 0; | ||
283 | } | ||
284 | #endif | ||