summaryrefslogtreecommitdiff
path: root/xdelta3/testing
diff options
context:
space:
mode:
authorjosh.macdonald <jmacd@users.noreply.github.com>2008-06-30 05:15:05 +0000
committerjosh.macdonald <jmacd@users.noreply.github.com>2008-06-30 05:15:05 +0000
commit9e896b470f5a4550a7fbbdc515db08b0249f5950 (patch)
tree8f2ea4d701f554a578a7d7e441f98e1f77425e9a /xdelta3/testing
parente127914b71638072798f7c02e93caf9377ba7385 (diff)
A test is taking shape...
Diffstat (limited to 'xdelta3/testing')
-rwxr-xr-xxdelta3/testing/Makefile4
-rw-r--r--xdelta3/testing/cmp.h37
-rw-r--r--xdelta3/testing/file.h172
-rw-r--r--xdelta3/testing/modify.h23
-rw-r--r--xdelta3/testing/random.h125
-rw-r--r--xdelta3/testing/regtest.cc173
-rw-r--r--xdelta3/testing/test.h59
-rw-r--r--xdelta3/testing/xdelta3-regtest.cc284
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 @@
1CFLAGS = -g -Wall -I.. -DXD3_DEBUG=1 -DNDEBUG=0 1CFLAGS = -g -Wall -I.. -DXD3_DEBUG=1 -DNDEBUG=0
2 2
3DEPS = ../*.h ../*.c *.cc 3DEPS = ../*.h ../*.c *.cc *.h
4 4
5TARGETS = xdelta3-regtest 5TARGETS = xdelta3-regtest
6 6
7all: $(TARGETS) 7all: $(TARGETS)
8 8
9xdelta3-regtest: $(DEPS) 9xdelta3-regtest: $(DEPS)
10 $(CXX) $(CFLAGS) xdelta3-regtest.cc -o xdelta3-regtest 10 $(CXX) $(CFLAGS) regtest.cc -o xdelta3-regtest
11 11
12clean: 12clean:
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++ -*- */
2namespace regtest {
3
4inline 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++ -*- */
2namespace regtest {
3
4class 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
17typedef map<xoff_t, Segment> SegmentMap;
18
19class Block;
20class BlockIterator;
21
22class 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
86class Block {
87public:
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
102private:
103 friend class BlockIterator;
104
105 size_t size_;
106 uint8_t *data_;
107};
108
109class BlockIterator {
110public:
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
133private:
134 const FileSpec& spec_;
135 xoff_t blkno_;
136};
137
138inline 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++ -*- */
2namespace regtest {
3
4class 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
8namespace regtest {
9
10class 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).
5const xoff_t Constants::BLOCK_SIZE;
6
7void 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
39void 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
69void 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
89int 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
98static 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
105int
106test_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
113static int
114test_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
3extern "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) \
16do {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>
30using std::cerr;
31using std::endl;
32
33#include <map>
34using std::map;
35using std::pair;
36
37template <typename T, typename U>
38pair<T, U> make_pair(const T& t, const U& u) {
39 return pair<T, U>(t, u);
40}
41
42class Constants {
43public:
44 static const xoff_t BLOCK_SIZE = 1 << 14;
45};
46
47using std::min;
48
49#include "random.h"
50using regtest::MTRandom;
51
52#include "file.h"
53using regtest::FileSpec;
54
55#include "modify.h"
56using regtest::Modify1stByte;
57
58#include "cmp.h"
59using 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
21extern "C" {
22#define NOT_MAIN 1
23#define REGRESSION_TEST 1
24#include "../xdelta3.c"
25}
26
27namespace {
28
29const int TEST_SEED1 = 0x1970;
30
31class 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
53int main(int argc, char **argv) {
54 RandomFileSpec spec1;
55
56 return 0;
57}
58
59
60#if 0
61static const int TESTS_PER_PARAMETER = 100;
62
63struct 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
73struct random_parameters_ {
74 int file_size;
75 int window_size;
76 int add_size;
77 int del_size;
78};
79
80typedef struct random_file_spec_ random_file_spec;
81typedef struct random_parameters_ random_parameters;
82
83static 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
90static random_parameters current_parameters;
91static int test2_malloc_count;
92
93void
94set_test_parameters (const random_parameters *params)
95{
96 current_parameters = *params;
97}
98
99void
100set_random_parameters ()
101{
102 // TODO(jmacd)
103 current_parameters = test_parameters[0];
104}
105
106void*
107test2_malloc (int size)
108{
109 test2_malloc_count++;
110 return malloc(size);
111}
112
113void
114test2_free (void *ptr)
115{
116 test2_malloc_count--;
117 free (ptr);
118 XD3_ASSERT (test2_malloc_count >= 0);
119}
120
121void
122random_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
145void
146random_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
154int
155random_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
177int
178random_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
192int
193random_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
210int
211random_file_spec_delta (random_file_spec *from, random_file_spec *to)
212{
213 return 0;
214}
215
216int
217test_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
224static int
225test_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