Show More
The requested changes are too big and content was truncated. Show full diff
@@ -0,0 +1,368 b'' | |||||
|
1 | //===- FuzzedDataProvider.h - Utility header for fuzz targets ---*- C++ -* ===// | |||
|
2 | // | |||
|
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |||
|
4 | // See https://llvm.org/LICENSE.txt for license information. | |||
|
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||
|
6 | // | |||
|
7 | //===----------------------------------------------------------------------===// | |||
|
8 | // A single header library providing an utility class to break up an array of | |||
|
9 | // bytes. Whenever run on the same input, provides the same output, as long as | |||
|
10 | // its methods are called in the same order, with the same arguments. | |||
|
11 | //===----------------------------------------------------------------------===// | |||
|
12 | ||||
|
13 | #ifndef LLVM_FUZZER_FUZZED_DATA_PROVIDER_H_ | |||
|
14 | #define LLVM_FUZZER_FUZZED_DATA_PROVIDER_H_ | |||
|
15 | ||||
|
16 | #include <algorithm> | |||
|
17 | #include <climits> | |||
|
18 | #include <cstddef> | |||
|
19 | #include <cstdint> | |||
|
20 | #include <cstring> | |||
|
21 | #include <initializer_list> | |||
|
22 | #include <string> | |||
|
23 | #include <type_traits> | |||
|
24 | #include <utility> | |||
|
25 | #include <vector> | |||
|
26 | ||||
|
27 | // In addition to the comments below, the API is also briefly documented at | |||
|
28 | // https://github.com/google/fuzzing/blob/master/docs/split-inputs.md#fuzzed-data-provider | |||
|
29 | class FuzzedDataProvider | |||
|
30 | { | |||
|
31 | public: | |||
|
32 | // |data| is an array of length |size| that the FuzzedDataProvider wraps | |||
|
33 | // to provide more granular access. |data| must outlive the | |||
|
34 | // FuzzedDataProvider. | |||
|
35 | FuzzedDataProvider(const uint8_t *data, size_t size) | |||
|
36 | : data_ptr_(data), remaining_bytes_(size) | |||
|
37 | { | |||
|
38 | } | |||
|
39 | ~FuzzedDataProvider() = default; | |||
|
40 | ||||
|
41 | // Returns a std::vector containing |num_bytes| of input data. If fewer | |||
|
42 | // than |num_bytes| of data remain, returns a shorter std::vector | |||
|
43 | // containing all of the data that's left. Can be used with any byte | |||
|
44 | // sized type, such as char, unsigned char, uint8_t, etc. | |||
|
45 | template <typename T> std::vector<T> ConsumeBytes(size_t num_bytes) | |||
|
46 | { | |||
|
47 | num_bytes = std::min(num_bytes, remaining_bytes_); | |||
|
48 | return ConsumeBytes<T>(num_bytes, num_bytes); | |||
|
49 | } | |||
|
50 | ||||
|
51 | // Similar to |ConsumeBytes|, but also appends the terminator value at | |||
|
52 | // the end of the resulting vector. Useful, when a mutable | |||
|
53 | // null-terminated C-string is needed, for example. But that is a rare | |||
|
54 | // case. Better avoid it, if possible, and prefer using |ConsumeBytes| | |||
|
55 | // or |ConsumeBytesAsString| methods. | |||
|
56 | template <typename T> | |||
|
57 | std::vector<T> ConsumeBytesWithTerminator(size_t num_bytes, | |||
|
58 | T terminator = 0) | |||
|
59 | { | |||
|
60 | num_bytes = std::min(num_bytes, remaining_bytes_); | |||
|
61 | std::vector<T> result = | |||
|
62 | ConsumeBytes<T>(num_bytes + 1, num_bytes); | |||
|
63 | result.back() = terminator; | |||
|
64 | return result; | |||
|
65 | } | |||
|
66 | ||||
|
67 | // Returns a std::string containing |num_bytes| of input data. Using | |||
|
68 | // this and | |||
|
69 | // |.c_str()| on the resulting string is the best way to get an | |||
|
70 | // immutable null-terminated C string. If fewer than |num_bytes| of data | |||
|
71 | // remain, returns a shorter std::string containing all of the data | |||
|
72 | // that's left. | |||
|
73 | std::string ConsumeBytesAsString(size_t num_bytes) | |||
|
74 | { | |||
|
75 | static_assert(sizeof(std::string::value_type) == | |||
|
76 | sizeof(uint8_t), | |||
|
77 | "ConsumeBytesAsString cannot convert the data to " | |||
|
78 | "a string."); | |||
|
79 | ||||
|
80 | num_bytes = std::min(num_bytes, remaining_bytes_); | |||
|
81 | std::string result( | |||
|
82 | reinterpret_cast<const std::string::value_type *>( | |||
|
83 | data_ptr_), | |||
|
84 | num_bytes); | |||
|
85 | Advance(num_bytes); | |||
|
86 | return result; | |||
|
87 | } | |||
|
88 | ||||
|
89 | // Returns a number in the range [min, max] by consuming bytes from the | |||
|
90 | // input data. The value might not be uniformly distributed in the given | |||
|
91 | // range. If there's no input data left, always returns |min|. |min| | |||
|
92 | // must be less than or equal to |max|. | |||
|
93 | template <typename T> T ConsumeIntegralInRange(T min, T max) | |||
|
94 | { | |||
|
95 | static_assert(std::is_integral<T>::value, | |||
|
96 | "An integral type is required."); | |||
|
97 | static_assert(sizeof(T) <= sizeof(uint64_t), | |||
|
98 | "Unsupported integral type."); | |||
|
99 | ||||
|
100 | if (min > max) | |||
|
101 | abort(); | |||
|
102 | ||||
|
103 | // Use the biggest type possible to hold the range and the | |||
|
104 | // result. | |||
|
105 | uint64_t range = static_cast<uint64_t>(max) - min; | |||
|
106 | uint64_t result = 0; | |||
|
107 | size_t offset = 0; | |||
|
108 | ||||
|
109 | while (offset < sizeof(T) * CHAR_BIT && (range >> offset) > 0 && | |||
|
110 | remaining_bytes_ != 0) { | |||
|
111 | // Pull bytes off the end of the seed data. | |||
|
112 | // Experimentally, this seems to allow the fuzzer to | |||
|
113 | // more easily explore the input space. This makes | |||
|
114 | // sense, since it works by modifying inputs that caused | |||
|
115 | // new code to run, and this data is often used to | |||
|
116 | // encode length of data read by |ConsumeBytes|. | |||
|
117 | // Separating out read lengths makes it easier modify | |||
|
118 | // the contents of the data that is actually read. | |||
|
119 | --remaining_bytes_; | |||
|
120 | result = | |||
|
121 | (result << CHAR_BIT) | data_ptr_[remaining_bytes_]; | |||
|
122 | offset += CHAR_BIT; | |||
|
123 | } | |||
|
124 | ||||
|
125 | // Avoid division by 0, in case |range + 1| results in overflow. | |||
|
126 | if (range != std::numeric_limits<decltype(range)>::max()) | |||
|
127 | result = result % (range + 1); | |||
|
128 | ||||
|
129 | return static_cast<T>(min + result); | |||
|
130 | } | |||
|
131 | ||||
|
132 | // Returns a std::string of length from 0 to |max_length|. When it runs | |||
|
133 | // out of input data, returns what remains of the input. Designed to be | |||
|
134 | // more stable with respect to a fuzzer inserting characters than just | |||
|
135 | // picking a random length and then consuming that many bytes with | |||
|
136 | // |ConsumeBytes|. | |||
|
137 | std::string ConsumeRandomLengthString(size_t max_length) | |||
|
138 | { | |||
|
139 | // Reads bytes from the start of |data_ptr_|. Maps "\\" to "\", | |||
|
140 | // and maps "\" followed by anything else to the end of the | |||
|
141 | // string. As a result of this logic, a fuzzer can insert | |||
|
142 | // characters into the string, and the string will be lengthened | |||
|
143 | // to include those new characters, resulting in a more stable | |||
|
144 | // fuzzer than picking the length of a string independently from | |||
|
145 | // picking its contents. | |||
|
146 | std::string result; | |||
|
147 | ||||
|
148 | // Reserve the anticipated capaticity to prevent several | |||
|
149 | // reallocations. | |||
|
150 | result.reserve(std::min(max_length, remaining_bytes_)); | |||
|
151 | for (size_t i = 0; i < max_length && remaining_bytes_ != 0; | |||
|
152 | ++i) { | |||
|
153 | char next = ConvertUnsignedToSigned<char>(data_ptr_[0]); | |||
|
154 | Advance(1); | |||
|
155 | if (next == '\\' && remaining_bytes_ != 0) { | |||
|
156 | next = | |||
|
157 | ConvertUnsignedToSigned<char>(data_ptr_[0]); | |||
|
158 | Advance(1); | |||
|
159 | if (next != '\\') | |||
|
160 | break; | |||
|
161 | } | |||
|
162 | result += next; | |||
|
163 | } | |||
|
164 | ||||
|
165 | result.shrink_to_fit(); | |||
|
166 | return result; | |||
|
167 | } | |||
|
168 | ||||
|
169 | // Returns a std::vector containing all remaining bytes of the input | |||
|
170 | // data. | |||
|
171 | template <typename T> std::vector<T> ConsumeRemainingBytes() | |||
|
172 | { | |||
|
173 | return ConsumeBytes<T>(remaining_bytes_); | |||
|
174 | } | |||
|
175 | ||||
|
176 | // Returns a std::string containing all remaining bytes of the input | |||
|
177 | // data. Prefer using |ConsumeRemainingBytes| unless you actually need a | |||
|
178 | // std::string object. | |||
|
179 | std::string ConsumeRemainingBytesAsString() | |||
|
180 | { | |||
|
181 | return ConsumeBytesAsString(remaining_bytes_); | |||
|
182 | } | |||
|
183 | ||||
|
184 | // Returns a number in the range [Type's min, Type's max]. The value | |||
|
185 | // might not be uniformly distributed in the given range. If there's no | |||
|
186 | // input data left, always returns |min|. | |||
|
187 | template <typename T> T ConsumeIntegral() | |||
|
188 | { | |||
|
189 | return ConsumeIntegralInRange(std::numeric_limits<T>::min(), | |||
|
190 | std::numeric_limits<T>::max()); | |||
|
191 | } | |||
|
192 | ||||
|
193 | // Reads one byte and returns a bool, or false when no data remains. | |||
|
194 | bool ConsumeBool() | |||
|
195 | { | |||
|
196 | return 1 & ConsumeIntegral<uint8_t>(); | |||
|
197 | } | |||
|
198 | ||||
|
199 | // Returns a copy of the value selected from the given fixed-size | |||
|
200 | // |array|. | |||
|
201 | template <typename T, size_t size> | |||
|
202 | T PickValueInArray(const T (&array)[size]) | |||
|
203 | { | |||
|
204 | static_assert(size > 0, "The array must be non empty."); | |||
|
205 | return array[ConsumeIntegralInRange<size_t>(0, size - 1)]; | |||
|
206 | } | |||
|
207 | ||||
|
208 | template <typename T> | |||
|
209 | T PickValueInArray(std::initializer_list<const T> list) | |||
|
210 | { | |||
|
211 | // TODO(Dor1s): switch to static_assert once C++14 is allowed. | |||
|
212 | if (!list.size()) | |||
|
213 | abort(); | |||
|
214 | ||||
|
215 | return *(list.begin() + | |||
|
216 | ConsumeIntegralInRange<size_t>(0, list.size() - 1)); | |||
|
217 | } | |||
|
218 | ||||
|
219 | // Returns an enum value. The enum must start at 0 and be contiguous. It | |||
|
220 | // must also contain |kMaxValue| aliased to its largest (inclusive) | |||
|
221 | // value. Such as: enum class Foo { SomeValue, OtherValue, kMaxValue = | |||
|
222 | // OtherValue }; | |||
|
223 | template <typename T> T ConsumeEnum() | |||
|
224 | { | |||
|
225 | static_assert(std::is_enum<T>::value, | |||
|
226 | "|T| must be an enum type."); | |||
|
227 | return static_cast<T>(ConsumeIntegralInRange<uint32_t>( | |||
|
228 | 0, static_cast<uint32_t>(T::kMaxValue))); | |||
|
229 | } | |||
|
230 | ||||
|
231 | // Returns a floating point number in the range [0.0, 1.0]. If there's | |||
|
232 | // no input data left, always returns 0. | |||
|
233 | template <typename T> T ConsumeProbability() | |||
|
234 | { | |||
|
235 | static_assert(std::is_floating_point<T>::value, | |||
|
236 | "A floating point type is required."); | |||
|
237 | ||||
|
238 | // Use different integral types for different floating point | |||
|
239 | // types in order to provide better density of the resulting | |||
|
240 | // values. | |||
|
241 | using IntegralType = | |||
|
242 | typename std::conditional<(sizeof(T) <= sizeof(uint32_t)), | |||
|
243 | uint32_t, uint64_t>::type; | |||
|
244 | ||||
|
245 | T result = static_cast<T>(ConsumeIntegral<IntegralType>()); | |||
|
246 | result /= | |||
|
247 | static_cast<T>(std::numeric_limits<IntegralType>::max()); | |||
|
248 | return result; | |||
|
249 | } | |||
|
250 | ||||
|
251 | // Returns a floating point value in the range [Type's lowest, Type's | |||
|
252 | // max] by consuming bytes from the input data. If there's no input data | |||
|
253 | // left, always returns approximately 0. | |||
|
254 | template <typename T> T ConsumeFloatingPoint() | |||
|
255 | { | |||
|
256 | return ConsumeFloatingPointInRange<T>( | |||
|
257 | std::numeric_limits<T>::lowest(), | |||
|
258 | std::numeric_limits<T>::max()); | |||
|
259 | } | |||
|
260 | ||||
|
261 | // Returns a floating point value in the given range by consuming bytes | |||
|
262 | // from the input data. If there's no input data left, returns |min|. | |||
|
263 | // Note that |min| must be less than or equal to |max|. | |||
|
264 | template <typename T> T ConsumeFloatingPointInRange(T min, T max) | |||
|
265 | { | |||
|
266 | if (min > max) | |||
|
267 | abort(); | |||
|
268 | ||||
|
269 | T range = .0; | |||
|
270 | T result = min; | |||
|
271 | constexpr T zero(.0); | |||
|
272 | if (max > zero && min < zero && | |||
|
273 | max > min + std::numeric_limits<T>::max()) { | |||
|
274 | // The diff |max - min| would overflow the given | |||
|
275 | // floating point type. Use the half of the diff as the | |||
|
276 | // range and consume a bool to decide whether the result | |||
|
277 | // is in the first of the second part of the diff. | |||
|
278 | range = (max / 2.0) - (min / 2.0); | |||
|
279 | if (ConsumeBool()) { | |||
|
280 | result += range; | |||
|
281 | } | |||
|
282 | } else { | |||
|
283 | range = max - min; | |||
|
284 | } | |||
|
285 | ||||
|
286 | return result + range * ConsumeProbability<T>(); | |||
|
287 | } | |||
|
288 | ||||
|
289 | // Reports the remaining bytes available for fuzzed input. | |||
|
290 | size_t remaining_bytes() | |||
|
291 | { | |||
|
292 | return remaining_bytes_; | |||
|
293 | } | |||
|
294 | ||||
|
295 | private: | |||
|
296 | FuzzedDataProvider(const FuzzedDataProvider &) = delete; | |||
|
297 | FuzzedDataProvider &operator=(const FuzzedDataProvider &) = delete; | |||
|
298 | ||||
|
299 | void Advance(size_t num_bytes) | |||
|
300 | { | |||
|
301 | if (num_bytes > remaining_bytes_) | |||
|
302 | abort(); | |||
|
303 | ||||
|
304 | data_ptr_ += num_bytes; | |||
|
305 | remaining_bytes_ -= num_bytes; | |||
|
306 | } | |||
|
307 | ||||
|
308 | template <typename T> | |||
|
309 | std::vector<T> ConsumeBytes(size_t size, size_t num_bytes_to_consume) | |||
|
310 | { | |||
|
311 | static_assert(sizeof(T) == sizeof(uint8_t), | |||
|
312 | "Incompatible data type."); | |||
|
313 | ||||
|
314 | // The point of using the size-based constructor below is to | |||
|
315 | // increase the odds of having a vector object with capacity | |||
|
316 | // being equal to the length. That part is always implementation | |||
|
317 | // specific, but at least both libc++ and libstdc++ allocate the | |||
|
318 | // requested number of bytes in that constructor, which seems to | |||
|
319 | // be a natural choice for other implementations as well. To | |||
|
320 | // increase the odds even more, we also call |shrink_to_fit| | |||
|
321 | // below. | |||
|
322 | std::vector<T> result(size); | |||
|
323 | if (size == 0) { | |||
|
324 | if (num_bytes_to_consume != 0) | |||
|
325 | abort(); | |||
|
326 | return result; | |||
|
327 | } | |||
|
328 | ||||
|
329 | std::memcpy(result.data(), data_ptr_, num_bytes_to_consume); | |||
|
330 | Advance(num_bytes_to_consume); | |||
|
331 | ||||
|
332 | // Even though |shrink_to_fit| is also implementation specific, | |||
|
333 | // we expect it to provide an additional assurance in case | |||
|
334 | // vector's constructor allocated a buffer which is larger than | |||
|
335 | // the actual amount of data we put inside it. | |||
|
336 | result.shrink_to_fit(); | |||
|
337 | return result; | |||
|
338 | } | |||
|
339 | ||||
|
340 | template <typename TS, typename TU> TS ConvertUnsignedToSigned(TU value) | |||
|
341 | { | |||
|
342 | static_assert(sizeof(TS) == sizeof(TU), | |||
|
343 | "Incompatible data types."); | |||
|
344 | static_assert(!std::numeric_limits<TU>::is_signed, | |||
|
345 | "Source type must be unsigned."); | |||
|
346 | ||||
|
347 | // TODO(Dor1s): change to `if constexpr` once C++17 becomes | |||
|
348 | // mainstream. | |||
|
349 | if (std::numeric_limits<TS>::is_modulo) | |||
|
350 | return static_cast<TS>(value); | |||
|
351 | ||||
|
352 | // Avoid using implementation-defined unsigned to signer | |||
|
353 | // conversions. To learn more, see | |||
|
354 | // https://stackoverflow.com/questions/13150449. | |||
|
355 | if (value <= std::numeric_limits<TS>::max()) { | |||
|
356 | return static_cast<TS>(value); | |||
|
357 | } else { | |||
|
358 | constexpr auto TS_min = std::numeric_limits<TS>::min(); | |||
|
359 | return TS_min + static_cast<char>(value - TS_min); | |||
|
360 | } | |||
|
361 | } | |||
|
362 | ||||
|
363 | const uint8_t *data_ptr_; | |||
|
364 | size_t remaining_bytes_; | |||
|
365 | }; | |||
|
366 | ||||
|
367 | #endif // LLVM_FUZZER_FUZZED_DATA_PROVIDER_H_ | |||
|
368 | // no-check-code since this is from a third party |
@@ -0,0 +1,29 b'' | |||||
|
1 | from __future__ import absolute_import, print_function | |||
|
2 | ||||
|
3 | import argparse | |||
|
4 | import zipfile | |||
|
5 | ||||
|
6 | ap = argparse.ArgumentParser() | |||
|
7 | ap.add_argument("out", metavar="some.zip", type=str, nargs=1) | |||
|
8 | args = ap.parse_args() | |||
|
9 | ||||
|
10 | with zipfile.ZipFile(args.out[0], "w", zipfile.ZIP_STORED) as zf: | |||
|
11 | zf.writestr( | |||
|
12 | "greek-tree", | |||
|
13 | "\n".join( | |||
|
14 | [ | |||
|
15 | "iota", | |||
|
16 | "A/mu", | |||
|
17 | "A/B/lambda", | |||
|
18 | "A/B/E/alpha", | |||
|
19 | "A/B/E/beta", | |||
|
20 | "A/D/gamma", | |||
|
21 | "A/D/G/pi", | |||
|
22 | "A/D/G/rho", | |||
|
23 | "A/D/G/tau", | |||
|
24 | "A/D/H/chi", | |||
|
25 | "A/D/H/omega", | |||
|
26 | "A/D/H/psi", | |||
|
27 | ] | |||
|
28 | ), | |||
|
29 | ) |
@@ -0,0 +1,45 b'' | |||||
|
1 | // Copyright 2017 Google Inc. All Rights Reserved. | |||
|
2 | // Licensed under the Apache License, Version 2.0 (the "License"); | |||
|
3 | ||||
|
4 | // Example of a standalone runner for "fuzz targets". | |||
|
5 | // It reads all files passed as parameters and feeds their contents | |||
|
6 | // one by one into the fuzz target (LLVMFuzzerTestOneInput). | |||
|
7 | // This runner does not do any fuzzing, but allows us to run the fuzz target | |||
|
8 | // on the test corpus (e.g. "do_stuff_test_data") or on a single file, | |||
|
9 | // e.g. the one that comes from a bug report. | |||
|
10 | ||||
|
11 | #include <cassert> | |||
|
12 | #include <fstream> | |||
|
13 | #include <iostream> | |||
|
14 | #include <vector> | |||
|
15 | ||||
|
16 | // Forward declare the "fuzz target" interface. | |||
|
17 | // We deliberately keep this inteface simple and header-free. | |||
|
18 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); | |||
|
19 | ||||
|
20 | extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv); | |||
|
21 | ||||
|
22 | int main(int argc, char **argv) | |||
|
23 | { | |||
|
24 | LLVMFuzzerInitialize(&argc, &argv); | |||
|
25 | ||||
|
26 | for (int i = 1; i < argc; i++) { | |||
|
27 | std::ifstream in(argv[i]); | |||
|
28 | in.seekg(0, in.end); | |||
|
29 | size_t length = in.tellg(); | |||
|
30 | in.seekg(0, in.beg); | |||
|
31 | std::cout << "Reading " << length << " bytes from " << argv[i] | |||
|
32 | << std::endl; | |||
|
33 | // Allocate exactly length bytes so that we reliably catch | |||
|
34 | // buffer overflows. | |||
|
35 | std::vector<char> bytes(length); | |||
|
36 | in.read(bytes.data(), bytes.size()); | |||
|
37 | assert(in); | |||
|
38 | LLVMFuzzerTestOneInput( | |||
|
39 | reinterpret_cast<const uint8_t *>(bytes.data()), | |||
|
40 | bytes.size()); | |||
|
41 | std::cout << "Execution successful" << std::endl; | |||
|
42 | } | |||
|
43 | return 0; | |||
|
44 | } | |||
|
45 | // no-check-code since this is from a third party |
@@ -0,0 +1,153 b'' | |||||
|
1 | # cli.py - Command line interface for automation | |||
|
2 | # | |||
|
3 | # Copyright 2019 Gregory Szorc <gregory.szorc@gmail.com> | |||
|
4 | # | |||
|
5 | # This software may be used and distributed according to the terms of the | |||
|
6 | # GNU General Public License version 2 or any later version. | |||
|
7 | ||||
|
8 | # no-check-code because Python 3 native. | |||
|
9 | ||||
|
10 | import argparse | |||
|
11 | import os | |||
|
12 | import pathlib | |||
|
13 | ||||
|
14 | from . import ( | |||
|
15 | inno, | |||
|
16 | wix, | |||
|
17 | ) | |||
|
18 | ||||
|
19 | HERE = pathlib.Path(os.path.abspath(os.path.dirname(__file__))) | |||
|
20 | SOURCE_DIR = HERE.parent.parent.parent | |||
|
21 | ||||
|
22 | ||||
|
23 | def build_inno(python=None, iscc=None, version=None): | |||
|
24 | if not os.path.isabs(python): | |||
|
25 | raise Exception("--python arg must be an absolute path") | |||
|
26 | ||||
|
27 | if iscc: | |||
|
28 | iscc = pathlib.Path(iscc) | |||
|
29 | else: | |||
|
30 | iscc = ( | |||
|
31 | pathlib.Path(os.environ["ProgramFiles(x86)"]) | |||
|
32 | / "Inno Setup 5" | |||
|
33 | / "ISCC.exe" | |||
|
34 | ) | |||
|
35 | ||||
|
36 | build_dir = SOURCE_DIR / "build" | |||
|
37 | ||||
|
38 | inno.build( | |||
|
39 | SOURCE_DIR, build_dir, pathlib.Path(python), iscc, version=version, | |||
|
40 | ) | |||
|
41 | ||||
|
42 | ||||
|
43 | def build_wix( | |||
|
44 | name=None, | |||
|
45 | python=None, | |||
|
46 | version=None, | |||
|
47 | sign_sn=None, | |||
|
48 | sign_cert=None, | |||
|
49 | sign_password=None, | |||
|
50 | sign_timestamp_url=None, | |||
|
51 | extra_packages_script=None, | |||
|
52 | extra_wxs=None, | |||
|
53 | extra_features=None, | |||
|
54 | ): | |||
|
55 | fn = wix.build_installer | |||
|
56 | kwargs = { | |||
|
57 | "source_dir": SOURCE_DIR, | |||
|
58 | "python_exe": pathlib.Path(python), | |||
|
59 | "version": version, | |||
|
60 | } | |||
|
61 | ||||
|
62 | if not os.path.isabs(python): | |||
|
63 | raise Exception("--python arg must be an absolute path") | |||
|
64 | ||||
|
65 | if extra_packages_script: | |||
|
66 | kwargs["extra_packages_script"] = extra_packages_script | |||
|
67 | if extra_wxs: | |||
|
68 | kwargs["extra_wxs"] = dict( | |||
|
69 | thing.split("=") for thing in extra_wxs.split(",") | |||
|
70 | ) | |||
|
71 | if extra_features: | |||
|
72 | kwargs["extra_features"] = extra_features.split(",") | |||
|
73 | ||||
|
74 | if sign_sn or sign_cert: | |||
|
75 | fn = wix.build_signed_installer | |||
|
76 | kwargs["name"] = name | |||
|
77 | kwargs["subject_name"] = sign_sn | |||
|
78 | kwargs["cert_path"] = sign_cert | |||
|
79 | kwargs["cert_password"] = sign_password | |||
|
80 | kwargs["timestamp_url"] = sign_timestamp_url | |||
|
81 | ||||
|
82 | fn(**kwargs) | |||
|
83 | ||||
|
84 | ||||
|
85 | def get_parser(): | |||
|
86 | parser = argparse.ArgumentParser() | |||
|
87 | ||||
|
88 | subparsers = parser.add_subparsers() | |||
|
89 | ||||
|
90 | sp = subparsers.add_parser("inno", help="Build Inno Setup installer") | |||
|
91 | sp.add_argument("--python", required=True, help="path to python.exe to use") | |||
|
92 | sp.add_argument("--iscc", help="path to iscc.exe to use") | |||
|
93 | sp.add_argument( | |||
|
94 | "--version", | |||
|
95 | help="Mercurial version string to use " | |||
|
96 | "(detected from __version__.py if not defined", | |||
|
97 | ) | |||
|
98 | sp.set_defaults(func=build_inno) | |||
|
99 | ||||
|
100 | sp = subparsers.add_parser( | |||
|
101 | "wix", help="Build Windows installer with WiX Toolset" | |||
|
102 | ) | |||
|
103 | sp.add_argument("--name", help="Application name", default="Mercurial") | |||
|
104 | sp.add_argument( | |||
|
105 | "--python", help="Path to Python executable to use", required=True | |||
|
106 | ) | |||
|
107 | sp.add_argument( | |||
|
108 | "--sign-sn", | |||
|
109 | help="Subject name (or fragment thereof) of certificate " | |||
|
110 | "to use for signing", | |||
|
111 | ) | |||
|
112 | sp.add_argument( | |||
|
113 | "--sign-cert", help="Path to certificate to use for signing" | |||
|
114 | ) | |||
|
115 | sp.add_argument("--sign-password", help="Password for signing certificate") | |||
|
116 | sp.add_argument( | |||
|
117 | "--sign-timestamp-url", | |||
|
118 | help="URL of timestamp server to use for signing", | |||
|
119 | ) | |||
|
120 | sp.add_argument("--version", help="Version string to use") | |||
|
121 | sp.add_argument( | |||
|
122 | "--extra-packages-script", | |||
|
123 | help=( | |||
|
124 | "Script to execute to include extra packages in " "py2exe binary." | |||
|
125 | ), | |||
|
126 | ) | |||
|
127 | sp.add_argument( | |||
|
128 | "--extra-wxs", help="CSV of path_to_wxs_file=working_dir_for_wxs_file" | |||
|
129 | ) | |||
|
130 | sp.add_argument( | |||
|
131 | "--extra-features", | |||
|
132 | help=( | |||
|
133 | "CSV of extra feature names to include " | |||
|
134 | "in the installer from the extra wxs files" | |||
|
135 | ), | |||
|
136 | ) | |||
|
137 | sp.set_defaults(func=build_wix) | |||
|
138 | ||||
|
139 | return parser | |||
|
140 | ||||
|
141 | ||||
|
142 | def main(): | |||
|
143 | parser = get_parser() | |||
|
144 | args = parser.parse_args() | |||
|
145 | ||||
|
146 | if not hasattr(args, "func"): | |||
|
147 | parser.print_help() | |||
|
148 | return | |||
|
149 | ||||
|
150 | kwargs = dict(vars(args)) | |||
|
151 | del kwargs["func"] | |||
|
152 | ||||
|
153 | args.func(**kwargs) |
@@ -0,0 +1,74 b'' | |||||
|
1 | #!/usr/bin/env python3 | |||
|
2 | # | |||
|
3 | # packaging.py - Mercurial packaging functionality | |||
|
4 | # | |||
|
5 | # Copyright 2019 Gregory Szorc <gregory.szorc@gmail.com> | |||
|
6 | # | |||
|
7 | # This software may be used and distributed according to the terms of the | |||
|
8 | # GNU General Public License version 2 or any later version. | |||
|
9 | ||||
|
10 | import os | |||
|
11 | import pathlib | |||
|
12 | import subprocess | |||
|
13 | import sys | |||
|
14 | import venv | |||
|
15 | ||||
|
16 | ||||
|
17 | HERE = pathlib.Path(os.path.abspath(__file__)).parent | |||
|
18 | REQUIREMENTS_TXT = HERE / "requirements.txt" | |||
|
19 | SOURCE_DIR = HERE.parent.parent | |||
|
20 | VENV = SOURCE_DIR / "build" / "venv-packaging" | |||
|
21 | ||||
|
22 | ||||
|
23 | def bootstrap(): | |||
|
24 | venv_created = not VENV.exists() | |||
|
25 | ||||
|
26 | VENV.parent.mkdir(exist_ok=True) | |||
|
27 | ||||
|
28 | venv.create(VENV, with_pip=True) | |||
|
29 | ||||
|
30 | if os.name == "nt": | |||
|
31 | venv_bin = VENV / "Scripts" | |||
|
32 | pip = venv_bin / "pip.exe" | |||
|
33 | python = venv_bin / "python.exe" | |||
|
34 | else: | |||
|
35 | venv_bin = VENV / "bin" | |||
|
36 | pip = venv_bin / "pip" | |||
|
37 | python = venv_bin / "python" | |||
|
38 | ||||
|
39 | args = [ | |||
|
40 | str(pip), | |||
|
41 | "install", | |||
|
42 | "-r", | |||
|
43 | str(REQUIREMENTS_TXT), | |||
|
44 | "--disable-pip-version-check", | |||
|
45 | ] | |||
|
46 | ||||
|
47 | if not venv_created: | |||
|
48 | args.append("-q") | |||
|
49 | ||||
|
50 | subprocess.run(args, check=True) | |||
|
51 | ||||
|
52 | os.environ["HGPACKAGING_BOOTSTRAPPED"] = "1" | |||
|
53 | os.environ["PATH"] = "%s%s%s" % (venv_bin, os.pathsep, os.environ["PATH"]) | |||
|
54 | ||||
|
55 | subprocess.run([str(python), __file__] + sys.argv[1:], check=True) | |||
|
56 | ||||
|
57 | ||||
|
58 | def run(): | |||
|
59 | import hgpackaging.cli as cli | |||
|
60 | ||||
|
61 | # Need to strip off main Python executable. | |||
|
62 | cli.main() | |||
|
63 | ||||
|
64 | ||||
|
65 | if __name__ == "__main__": | |||
|
66 | try: | |||
|
67 | if "HGPACKAGING_BOOTSTRAPPED" not in os.environ: | |||
|
68 | bootstrap() | |||
|
69 | else: | |||
|
70 | run() | |||
|
71 | except subprocess.CalledProcessError as e: | |||
|
72 | sys.exit(e.returncode) | |||
|
73 | except KeyboardInterrupt: | |||
|
74 | sys.exit(1) |
@@ -0,0 +1,39 b'' | |||||
|
1 | # | |||
|
2 | # This file is autogenerated by pip-compile | |||
|
3 | # To update, run: | |||
|
4 | # | |||
|
5 | # pip-compile --generate-hashes --output-file=contrib/packaging/requirements.txt contrib/packaging/requirements.txt.in | |||
|
6 | # | |||
|
7 | jinja2==2.10.3 \ | |||
|
8 | --hash=sha256:74320bb91f31270f9551d46522e33af46a80c3d619f4a4bf42b3164d30b5911f \ | |||
|
9 | --hash=sha256:9fe95f19286cfefaa917656583d020be14e7859c6b0252588391e47db34527de | |||
|
10 | markupsafe==1.1.1 \ | |||
|
11 | --hash=sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473 \ | |||
|
12 | --hash=sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161 \ | |||
|
13 | --hash=sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235 \ | |||
|
14 | --hash=sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5 \ | |||
|
15 | --hash=sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff \ | |||
|
16 | --hash=sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b \ | |||
|
17 | --hash=sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1 \ | |||
|
18 | --hash=sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e \ | |||
|
19 | --hash=sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183 \ | |||
|
20 | --hash=sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66 \ | |||
|
21 | --hash=sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1 \ | |||
|
22 | --hash=sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1 \ | |||
|
23 | --hash=sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e \ | |||
|
24 | --hash=sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b \ | |||
|
25 | --hash=sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905 \ | |||
|
26 | --hash=sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735 \ | |||
|
27 | --hash=sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d \ | |||
|
28 | --hash=sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e \ | |||
|
29 | --hash=sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d \ | |||
|
30 | --hash=sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c \ | |||
|
31 | --hash=sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21 \ | |||
|
32 | --hash=sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2 \ | |||
|
33 | --hash=sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5 \ | |||
|
34 | --hash=sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b \ | |||
|
35 | --hash=sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6 \ | |||
|
36 | --hash=sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f \ | |||
|
37 | --hash=sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f \ | |||
|
38 | --hash=sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7 \ | |||
|
39 | # via jinja2 |
@@ -0,0 +1,1 b'' | |||||
|
1 | jinja2 |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
@@ -1,5 +1,6 b'' | |||||
1 | { |
|
1 | { | |
2 | "conduit_uri": "https://phab.mercurial-scm.org/api", |
|
2 | "conduit_uri": "https://phab.mercurial-scm.org/api", | |
|
3 | "phabricator.uri": "https://phab.mercurial-scm.org/", | |||
3 | "repository.callsign": "HG", |
|
4 | "repository.callsign": "HG", | |
4 | "arc.land.onto.default": "@", |
|
5 | "arc.land.onto.default": "@", | |
5 | "base": "hg:.^" |
|
6 | "base": "hg:.^" |
@@ -51,6 +51,7 b' tags' | |||||
51 | cscope.* |
|
51 | cscope.* | |
52 | .idea/* |
|
52 | .idea/* | |
53 | .asv/* |
|
53 | .asv/* | |
|
54 | .pytype/* | |||
54 | i18n/hg.pot |
|
55 | i18n/hg.pot | |
55 | locale/*/LC_MESSAGES/hg.mo |
|
56 | locale/*/LC_MESSAGES/hg.mo | |
56 | hgext/__index__.py |
|
57 | hgext/__index__.py |
@@ -11,7 +11,7 b' HGPYTHONS ?= $(HGROOT)/build/pythons' | |||||
11 | PURE= |
|
11 | PURE= | |
12 | PYFILESCMD=find mercurial hgext doc -name '*.py' |
|
12 | PYFILESCMD=find mercurial hgext doc -name '*.py' | |
13 | PYFILES:=$(shell $(PYFILESCMD)) |
|
13 | PYFILES:=$(shell $(PYFILESCMD)) | |
14 | DOCFILES=mercurial/help/*.txt |
|
14 | DOCFILES=mercurial/helptext/*.txt | |
15 | export LANGUAGE=C |
|
15 | export LANGUAGE=C | |
16 | export LC_ALL=C |
|
16 | export LC_ALL=C | |
17 | TESTFLAGS ?= $(shell echo $$HGTESTFLAGS) |
|
17 | TESTFLAGS ?= $(shell echo $$HGTESTFLAGS) | |
@@ -189,7 +189,8 b' packaging_targets := \\' | |||||
189 | docker-centos6 \ |
|
189 | docker-centos6 \ | |
190 | docker-centos7 \ |
|
190 | docker-centos7 \ | |
191 | docker-centos8 \ |
|
191 | docker-centos8 \ | |
192 |
docker-debian- |
|
192 | docker-debian-bullseye \ | |
|
193 | docker-debian-buster \ | |||
193 | docker-debian-stretch \ |
|
194 | docker-debian-stretch \ | |
194 | docker-fedora \ |
|
195 | docker-fedora \ | |
195 | docker-ubuntu-trusty \ |
|
196 | docker-ubuntu-trusty \ |
@@ -59,7 +59,7 b" DEBIAN_ACCOUNT_ID_2 = '136693071363'" | |||||
59 | UBUNTU_ACCOUNT_ID = '099720109477' |
|
59 | UBUNTU_ACCOUNT_ID = '099720109477' | |
60 |
|
60 | |||
61 |
|
61 | |||
62 |
WINDOWS_BASE_IMAGE_NAME = 'Windows_Server-2019-English-Full-Base-2019. |
|
62 | WINDOWS_BASE_IMAGE_NAME = 'Windows_Server-2019-English-Full-Base-2019.11.13' | |
63 |
|
63 | |||
64 |
|
64 | |||
65 | KEY_PAIRS = { |
|
65 | KEY_PAIRS = { |
@@ -71,7 +71,7 b' Write-Output "updated Mercurial working ' | |||||
71 | BUILD_INNO = r''' |
|
71 | BUILD_INNO = r''' | |
72 | Set-Location C:\hgdev\src |
|
72 | Set-Location C:\hgdev\src | |
73 | $python = "C:\hgdev\python27-{arch}\python.exe" |
|
73 | $python = "C:\hgdev\python27-{arch}\python.exe" | |
74 |
C:\hgdev\python37-x64\python.exe contrib\packaging\ |
|
74 | C:\hgdev\python37-x64\python.exe contrib\packaging\packaging.py inno --python $python | |
75 | if ($LASTEXITCODE -ne 0) {{ |
|
75 | if ($LASTEXITCODE -ne 0) {{ | |
76 | throw "process exited non-0: $LASTEXITCODE" |
|
76 | throw "process exited non-0: $LASTEXITCODE" | |
77 | }} |
|
77 | }} | |
@@ -88,7 +88,7 b' if ($LASTEXITCODE -ne 0) {{' | |||||
88 | BUILD_WIX = r''' |
|
88 | BUILD_WIX = r''' | |
89 | Set-Location C:\hgdev\src |
|
89 | Set-Location C:\hgdev\src | |
90 | $python = "C:\hgdev\python27-{arch}\python.exe" |
|
90 | $python = "C:\hgdev\python27-{arch}\python.exe" | |
91 |
C:\hgdev\python37-x64\python.exe contrib\packaging\ |
|
91 | C:\hgdev\python37-x64\python.exe contrib\packaging\packaging.py wix --python $python {extra_args} | |
92 | if ($LASTEXITCODE -ne 0) {{ |
|
92 | if ($LASTEXITCODE -ne 0) {{ | |
93 | throw "process exited non-0: $LASTEXITCODE" |
|
93 | throw "process exited non-0: $LASTEXITCODE" | |
94 | }} |
|
94 | }} |
@@ -281,10 +281,10 b' for i in [0, 1]:' | |||||
281 | for tp in testpats[i]: |
|
281 | for tp in testpats[i]: | |
282 | p = tp[0] |
|
282 | p = tp[0] | |
283 | m = tp[1] |
|
283 | m = tp[1] | |
284 |
if p.startswith( |
|
284 | if p.startswith('^'): | |
285 |
p = |
|
285 | p = "^ [$>] (%s)" % p[1:] | |
286 | else: |
|
286 | else: | |
287 |
p = |
|
287 | p = "^ [$>] .*(%s)" % p | |
288 | utestpats[i].append((p, m) + tp[2:]) |
|
288 | utestpats[i].append((p, m) + tp[2:]) | |
289 |
|
289 | |||
290 | # don't transform the following rules: |
|
290 | # don't transform the following rules: |
@@ -27,32 +27,42 b' beforepatch = afterheader + r"(?!\\n(?!@@' | |||||
27 |
|
27 | |||
28 | errors = [ |
|
28 | errors = [ | |
29 | (beforepatch + r".*[(]bc[)]", "(BC) needs to be uppercase"), |
|
29 | (beforepatch + r".*[(]bc[)]", "(BC) needs to be uppercase"), | |
30 | (beforepatch + r".*[(]issue \d\d\d", |
|
30 | ( | |
31 | "no space allowed between issue and number"), |
|
31 | beforepatch + r".*[(]issue \d\d\d", | |
|
32 | "no space allowed between issue and number", | |||
|
33 | ), | |||
32 | (beforepatch + r".*[(]bug(\d|\s)", "use (issueDDDD) instead of bug"), |
|
34 | (beforepatch + r".*[(]bug(\d|\s)", "use (issueDDDD) instead of bug"), | |
33 | (commitheader + r"# User [^@\n]+\n", "username is not an email address"), |
|
35 | (commitheader + r"# User [^@\n]+\n", "username is not an email address"), | |
34 | (commitheader + r"(?!merge with )[^#]\S+[^:] ", |
|
36 | ( | |
35 | "summary line doesn't start with 'topic: '"), |
|
37 | commitheader + r"(?!merge with )[^#]\S+[^:] ", | |
|
38 | "summary line doesn't start with 'topic: '", | |||
|
39 | ), | |||
36 | (afterheader + r"[A-Z][a-z]\S+", "don't capitalize summary lines"), |
|
40 | (afterheader + r"[A-Z][a-z]\S+", "don't capitalize summary lines"), | |
37 | (afterheader + r"^\S+: *[A-Z][a-z]\S+", "don't capitalize summary lines"), |
|
41 | (afterheader + r"^\S+: *[A-Z][a-z]\S+", "don't capitalize summary lines"), | |
38 | (afterheader + r"\S*[^A-Za-z0-9-_]\S*: ", |
|
42 | ( | |
39 | "summary keyword should be most user-relevant one-word command or topic"), |
|
43 | afterheader + r"\S*[^A-Za-z0-9-_]\S*: ", | |
|
44 | "summary keyword should be most user-relevant one-word command or topic", | |||
|
45 | ), | |||
40 | (afterheader + r".*\.\s*\n", "don't add trailing period on summary line"), |
|
46 | (afterheader + r".*\.\s*\n", "don't add trailing period on summary line"), | |
41 | (afterheader + r".{79,}", "summary line too long (limit is 78)"), |
|
47 | (afterheader + r".{79,}", "summary line too long (limit is 78)"), | |
42 | ] |
|
48 | ] | |
43 |
|
49 | |||
44 | word = re.compile(r'\S') |
|
50 | word = re.compile(r'\S') | |
|
51 | ||||
|
52 | ||||
45 | def nonempty(first, second): |
|
53 | def nonempty(first, second): | |
46 | if word.search(first): |
|
54 | if word.search(first): | |
47 | return first |
|
55 | return first | |
48 | return second |
|
56 | return second | |
49 |
|
57 | |||
|
58 | ||||
50 | def checkcommit(commit, node=None): |
|
59 | def checkcommit(commit, node=None): | |
51 | exitcode = 0 |
|
60 | exitcode = 0 | |
52 | printed = node is None |
|
61 | printed = node is None | |
53 | hits = [] |
|
62 | hits = [] | |
54 |
signtag = ( |
|
63 | signtag = ( | |
55 |
r'Added (tag [^ ]+|signature) for changeset [a-f0-9]{12}' |
|
64 | afterheader + r'Added (tag [^ ]+|signature) for changeset [a-f0-9]{12}' | |
|
65 | ) | |||
56 | if re.search(signtag, commit): |
|
66 | if re.search(signtag, commit): | |
57 | return 0 |
|
67 | return 0 | |
58 | for exp, msg in errors: |
|
68 | for exp, msg in errors: | |
@@ -84,9 +94,11 b' def checkcommit(commit, node=None):' | |||||
84 |
|
94 | |||
85 | return exitcode |
|
95 | return exitcode | |
86 |
|
96 | |||
|
97 | ||||
87 | def readcommit(node): |
|
98 | def readcommit(node): | |
88 | return os.popen("hg export %s" % node).read() |
|
99 | return os.popen("hg export %s" % node).read() | |
89 |
|
100 | |||
|
101 | ||||
90 | if __name__ == "__main__": |
|
102 | if __name__ == "__main__": | |
91 | exitcode = 0 |
|
103 | exitcode = 0 | |
92 | node = os.environ.get("HG_NODE") |
|
104 | node = os.environ.get("HG_NODE") |
@@ -3,100 +3,9 b'' | |||||
3 | mercurial/cext/manifest.c |
|
3 | mercurial/cext/manifest.c | |
4 | mercurial/cext/osutil.c |
|
4 | mercurial/cext/osutil.c | |
5 | # Vendored code that we should never format: |
|
5 | # Vendored code that we should never format: | |
6 | contrib/python-zstandard/c-ext/bufferutil.c |
|
6 | syntax: glob | |
7 |
contrib/python-zstandard/ |
|
7 | contrib/python-zstandard/**.c | |
8 |
contrib/python-zstandard/ |
|
8 | contrib/python-zstandard/**.h | |
9 | contrib/python-zstandard/c-ext/compressionparams.c |
|
9 | hgext/fsmonitor/pywatchman/**.c | |
10 | contrib/python-zstandard/c-ext/compressionreader.c |
|
10 | mercurial/thirdparty/**.c | |
11 | contrib/python-zstandard/c-ext/compressionwriter.c |
|
11 | mercurial/thirdparty/**.h | |
12 | contrib/python-zstandard/c-ext/compressobj.c |
|
|||
13 | contrib/python-zstandard/c-ext/compressor.c |
|
|||
14 | contrib/python-zstandard/c-ext/compressoriterator.c |
|
|||
15 | contrib/python-zstandard/c-ext/constants.c |
|
|||
16 | contrib/python-zstandard/c-ext/decompressionreader.c |
|
|||
17 | contrib/python-zstandard/c-ext/decompressionwriter.c |
|
|||
18 | contrib/python-zstandard/c-ext/decompressobj.c |
|
|||
19 | contrib/python-zstandard/c-ext/decompressor.c |
|
|||
20 | contrib/python-zstandard/c-ext/decompressoriterator.c |
|
|||
21 | contrib/python-zstandard/c-ext/frameparams.c |
|
|||
22 | contrib/python-zstandard/c-ext/python-zstandard.h |
|
|||
23 | contrib/python-zstandard/zstd.c |
|
|||
24 | contrib/python-zstandard/zstd/common/bitstream.h |
|
|||
25 | contrib/python-zstandard/zstd/common/compiler.h |
|
|||
26 | contrib/python-zstandard/zstd/common/cpu.h |
|
|||
27 | contrib/python-zstandard/zstd/common/debug.c |
|
|||
28 | contrib/python-zstandard/zstd/common/debug.h |
|
|||
29 | contrib/python-zstandard/zstd/common/entropy_common.c |
|
|||
30 | contrib/python-zstandard/zstd/common/error_private.c |
|
|||
31 | contrib/python-zstandard/zstd/common/error_private.h |
|
|||
32 | contrib/python-zstandard/zstd/common/fse_decompress.c |
|
|||
33 | contrib/python-zstandard/zstd/common/fse.h |
|
|||
34 | contrib/python-zstandard/zstd/common/huf.h |
|
|||
35 | contrib/python-zstandard/zstd/common/mem.h |
|
|||
36 | contrib/python-zstandard/zstd/common/pool.c |
|
|||
37 | contrib/python-zstandard/zstd/common/pool.h |
|
|||
38 | contrib/python-zstandard/zstd/common/threading.c |
|
|||
39 | contrib/python-zstandard/zstd/common/threading.h |
|
|||
40 | contrib/python-zstandard/zstd/common/xxhash.c |
|
|||
41 | contrib/python-zstandard/zstd/common/xxhash.h |
|
|||
42 | contrib/python-zstandard/zstd/common/zstd_common.c |
|
|||
43 | contrib/python-zstandard/zstd/common/zstd_errors.h |
|
|||
44 | contrib/python-zstandard/zstd/common/zstd_internal.h |
|
|||
45 | contrib/python-zstandard/zstd/compress/fse_compress.c |
|
|||
46 | contrib/python-zstandard/zstd/compress/hist.c |
|
|||
47 | contrib/python-zstandard/zstd/compress/hist.h |
|
|||
48 | contrib/python-zstandard/zstd/compress/huf_compress.c |
|
|||
49 | contrib/python-zstandard/zstd/compress/zstd_compress.c |
|
|||
50 | contrib/python-zstandard/zstd/compress/zstd_compress_internal.h |
|
|||
51 | contrib/python-zstandard/zstd/compress/zstd_compress_literals.c |
|
|||
52 | contrib/python-zstandard/zstd/compress/zstd_compress_literals.h |
|
|||
53 | contrib/python-zstandard/zstd/compress/zstd_compress_sequences.c |
|
|||
54 | contrib/python-zstandard/zstd/compress/zstd_compress_sequences.h |
|
|||
55 | contrib/python-zstandard/zstd/compress/zstd_double_fast.c |
|
|||
56 | contrib/python-zstandard/zstd/compress/zstd_double_fast.h |
|
|||
57 | contrib/python-zstandard/zstd/compress/zstd_fast.c |
|
|||
58 | contrib/python-zstandard/zstd/compress/zstd_fast.h |
|
|||
59 | contrib/python-zstandard/zstd/compress/zstd_lazy.c |
|
|||
60 | contrib/python-zstandard/zstd/compress/zstd_lazy.h |
|
|||
61 | contrib/python-zstandard/zstd/compress/zstd_ldm.c |
|
|||
62 | contrib/python-zstandard/zstd/compress/zstd_ldm.h |
|
|||
63 | contrib/python-zstandard/zstd/compress/zstdmt_compress.c |
|
|||
64 | contrib/python-zstandard/zstd/compress/zstdmt_compress.h |
|
|||
65 | contrib/python-zstandard/zstd/compress/zstd_opt.c |
|
|||
66 | contrib/python-zstandard/zstd/compress/zstd_opt.h |
|
|||
67 | contrib/python-zstandard/zstd/decompress/huf_decompress.c |
|
|||
68 | contrib/python-zstandard/zstd/decompress/zstd_ddict.c |
|
|||
69 | contrib/python-zstandard/zstd/decompress/zstd_ddict.h |
|
|||
70 | contrib/python-zstandard/zstd/decompress/zstd_decompress_block.c |
|
|||
71 | contrib/python-zstandard/zstd/decompress/zstd_decompress_block.h |
|
|||
72 | contrib/python-zstandard/zstd/decompress/zstd_decompress_internal.h |
|
|||
73 | contrib/python-zstandard/zstd/decompress/zstd_decompress.c |
|
|||
74 | contrib/python-zstandard/zstd/deprecated/zbuff_common.c |
|
|||
75 | contrib/python-zstandard/zstd/deprecated/zbuff_compress.c |
|
|||
76 | contrib/python-zstandard/zstd/deprecated/zbuff_decompress.c |
|
|||
77 | contrib/python-zstandard/zstd/deprecated/zbuff.h |
|
|||
78 | contrib/python-zstandard/zstd/dictBuilder/cover.c |
|
|||
79 | contrib/python-zstandard/zstd/dictBuilder/cover.h |
|
|||
80 | contrib/python-zstandard/zstd/dictBuilder/divsufsort.c |
|
|||
81 | contrib/python-zstandard/zstd/dictBuilder/divsufsort.h |
|
|||
82 | contrib/python-zstandard/zstd/dictBuilder/fastcover.c |
|
|||
83 | contrib/python-zstandard/zstd/dictBuilder/zdict.c |
|
|||
84 | contrib/python-zstandard/zstd/dictBuilder/zdict.h |
|
|||
85 | contrib/python-zstandard/zstd/zstd.h |
|
|||
86 | hgext/fsmonitor/pywatchman/bser.c |
|
|||
87 | mercurial/thirdparty/xdiff/xdiff.h |
|
|||
88 | mercurial/thirdparty/xdiff/xdiffi.c |
|
|||
89 | mercurial/thirdparty/xdiff/xdiffi.h |
|
|||
90 | mercurial/thirdparty/xdiff/xemit.c |
|
|||
91 | mercurial/thirdparty/xdiff/xemit.h |
|
|||
92 | mercurial/thirdparty/xdiff/xhistogram.c |
|
|||
93 | mercurial/thirdparty/xdiff/xinclude.h |
|
|||
94 | mercurial/thirdparty/xdiff/xmacros.h |
|
|||
95 | mercurial/thirdparty/xdiff/xmerge.c |
|
|||
96 | mercurial/thirdparty/xdiff/xpatience.c |
|
|||
97 | mercurial/thirdparty/xdiff/xprepare.c |
|
|||
98 | mercurial/thirdparty/xdiff/xprepare.h |
|
|||
99 | mercurial/thirdparty/xdiff/xtypes.h |
|
|||
100 | mercurial/thirdparty/xdiff/xutils.c |
|
|||
101 | mercurial/thirdparty/xdiff/xutils.h |
|
|||
102 | mercurial/thirdparty/zope/interface/_zope_interface_coptimizations.c |
|
@@ -11,23 +11,26 b' from mercurial import (' | |||||
11 | pycompat, |
|
11 | pycompat, | |
12 | revlog, |
|
12 | revlog, | |
13 | ) |
|
13 | ) | |
14 |
from mercurial.utils import |
|
14 | from mercurial.utils import procutil | |
15 | procutil, |
|
|||
16 | ) |
|
|||
17 |
|
15 | |||
18 | for fp in (sys.stdin, sys.stdout, sys.stderr): |
|
16 | for fp in (sys.stdin, sys.stdout, sys.stderr): | |
19 | procutil.setbinary(fp) |
|
17 | procutil.setbinary(fp) | |
20 |
|
18 | |||
|
19 | ||||
21 | def binopen(path, mode=b'rb'): |
|
20 | def binopen(path, mode=b'rb'): | |
22 | if b'b' not in mode: |
|
21 | if b'b' not in mode: | |
23 | mode = mode + b'b' |
|
22 | mode = mode + b'b' | |
24 | return open(path, pycompat.sysstr(mode)) |
|
23 | return open(path, pycompat.sysstr(mode)) | |
|
24 | ||||
|
25 | ||||
25 | binopen.options = {} |
|
26 | binopen.options = {} | |
26 |
|
27 | |||
|
28 | ||||
27 | def printb(data, end=b'\n'): |
|
29 | def printb(data, end=b'\n'): | |
28 | sys.stdout.flush() |
|
30 | sys.stdout.flush() | |
29 | pycompat.stdout.write(data + end) |
|
31 | pycompat.stdout.write(data + end) | |
30 |
|
32 | |||
|
33 | ||||
31 | for f in sys.argv[1:]: |
|
34 | for f in sys.argv[1:]: | |
32 | r = revlog.revlog(binopen, encoding.strtolocal(f)) |
|
35 | r = revlog.revlog(binopen, encoding.strtolocal(f)) | |
33 | print("file:", f) |
|
36 | print("file:", f) |
@@ -1,9 +1,14 b'' | |||||
1 | [fix] |
|
1 | [fix] | |
2 |
clang-format:command = clang-format --style file |
|
2 | clang-format:command = clang-format --style file | |
3 |
clang-format:pattern = (**.c or **.cc or **.h) and not " |
|
3 | clang-format:pattern = set:(**.c or **.cc or **.h) and not "include:contrib/clang-format-ignorelist" | |
4 |
|
4 | |||
5 |
rustfmt:command = rustfmt |
|
5 | rustfmt:command = rustfmt +nightly | |
6 | rustfmt:pattern = set:**.rs |
|
6 | rustfmt:pattern = set:**.rs | |
7 |
|
7 | |||
8 | black:command = black --config=black.toml - |
|
8 | black:command = black --config=black.toml - | |
9 | black:pattern = set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**" |
|
9 | black:pattern = set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**" | |
|
10 | ||||
|
11 | # Mercurial doesn't have any Go code, but if we did this is how we | |||
|
12 | # would configure `hg fix` for Go: | |||
|
13 | go:command = gofmt | |||
|
14 | go:pattern = set:**.go |
@@ -1,184 +1,129 b'' | |||||
1 | CC = clang |
|
1 | CC = clang | |
2 | CXX = clang++ |
|
2 | CXX = clang++ | |
3 |
|
3 | |||
4 | all: bdiff mpatch xdiff |
|
4 | # By default, use our own standalone_fuzz_target_runner. | |
|
5 | # This runner does no fuzzing, but simply executes the inputs | |||
|
6 | # provided via parameters. | |||
|
7 | # Run e.g. "make all LIB_FUZZING_ENGINE=/path/to/libFuzzer.a" | |||
|
8 | # to link the fuzzer(s) against a real fuzzing engine. | |||
|
9 | # | |||
|
10 | # OSS-Fuzz will define its own value for LIB_FUZZING_ENGINE. | |||
|
11 | LIB_FUZZING_ENGINE ?= standalone_fuzz_target_runner.o | |||
5 |
|
12 | |||
6 | fuzzutil.o: fuzzutil.cc fuzzutil.h |
|
13 | PYTHON_CONFIG ?= $$OUT/sanpy/bin/python-config | |
7 | $(CXX) $(CXXFLAGS) -g -O1 \ |
|
14 | ||
8 | -std=c++17 \ |
|
15 | CXXFLAGS += -Wno-deprecated-register | |
9 | -I../../mercurial -c -o fuzzutil.o fuzzutil.cc |
|
|||
10 |
|
16 | |||
11 | fuzzutil-oss-fuzz.o: fuzzutil.cc fuzzutil.h |
|
17 | all: standalone_fuzz_target_runner.o oss-fuzz | |
12 | $(CXX) $(CXXFLAGS) -std=c++17 \ |
|
18 | ||
13 | -I../../mercurial -c -o fuzzutil-oss-fuzz.o fuzzutil.cc |
|
19 | standalone_fuzz_target_runner.o: standalone_fuzz_target_runner.cc | |
|
20 | ||||
|
21 | $$OUT/%_fuzzer_seed_corpus.zip: %_corpus.py | |||
|
22 | python $< $@ | |||
14 |
|
23 | |||
15 | pyutil.o: pyutil.cc pyutil.h |
|
24 | pyutil.o: pyutil.cc pyutil.h | |
16 | $(CXX) $(CXXFLAGS) -g -O1 \ |
|
25 | $(CXX) $(CXXFLAGS) -g -O1 \ | |
17 | `$$OUT/sanpy/bin/python-config --cflags` \ |
|
26 | `$(PYTHON_CONFIG) --cflags` \ | |
18 | -I../../mercurial -c -o pyutil.o pyutil.cc |
|
27 | -I../../mercurial -c -o pyutil.o pyutil.cc | |
19 |
|
28 | |||
20 | bdiff.o: ../../mercurial/bdiff.c |
|
|||
21 | $(CC) $(CFLAGS) -fsanitize=fuzzer-no-link,address -c -o bdiff.o \ |
|
|||
22 | ../../mercurial/bdiff.c |
|
|||
23 |
|
||||
24 | bdiff: bdiff.cc bdiff.o fuzzutil.o |
|
|||
25 | $(CXX) $(CXXFLAGS) -DHG_FUZZER_INCLUDE_MAIN=1 -g -O1 -fsanitize=fuzzer-no-link,address \ |
|
|||
26 | -std=c++17 \ |
|
|||
27 | -I../../mercurial bdiff.cc bdiff.o fuzzutil.o -o bdiff |
|
|||
28 |
|
||||
29 | bdiff-oss-fuzz.o: ../../mercurial/bdiff.c |
|
29 | bdiff-oss-fuzz.o: ../../mercurial/bdiff.c | |
30 | $(CC) $(CFLAGS) -c -o bdiff-oss-fuzz.o ../../mercurial/bdiff.c |
|
30 | $(CC) $(CFLAGS) -c -o bdiff-oss-fuzz.o ../../mercurial/bdiff.c | |
31 |
|
31 | |||
32 |
bdiff_fuzzer: bdiff.cc bdiff-oss-fuzz.o |
|
32 | bdiff_fuzzer: bdiff.cc bdiff-oss-fuzz.o | |
33 | $(CXX) $(CXXFLAGS) -std=c++17 -I../../mercurial bdiff.cc \ |
|
33 | $(CXX) $(CXXFLAGS) -std=c++17 -I../../mercurial bdiff.cc \ | |
34 | bdiff-oss-fuzz.o fuzzutil-oss-fuzz.o -lFuzzingEngine -o \ |
|
34 | bdiff-oss-fuzz.o $(LIB_FUZZING_ENGINE) -o \ | |
35 | $$OUT/bdiff_fuzzer |
|
35 | $$OUT/bdiff_fuzzer | |
36 |
|
36 | |||
37 | mpatch.o: ../../mercurial/mpatch.c |
|
37 | mpatch.o: ../../mercurial/mpatch.c | |
38 | $(CC) -g -O1 -fsanitize=fuzzer-no-link,address -c -o mpatch.o \ |
|
38 | $(CC) -g -O1 -fsanitize=fuzzer-no-link,address -c -o mpatch.o \ | |
39 | ../../mercurial/mpatch.c |
|
39 | ../../mercurial/mpatch.c | |
40 |
|
40 | |||
41 | mpatch: CXXFLAGS += -std=c++17 |
|
|||
42 | mpatch: mpatch.cc mpatch.o fuzzutil.o |
|
|||
43 | $(CXX) $(CXXFLAGS) -DHG_FUZZER_INCLUDE_MAIN=1 -g -O1 -fsanitize=fuzzer-no-link,address \ |
|
|||
44 | -I../../mercurial mpatch.cc mpatch.o fuzzutil.o -o mpatch |
|
|||
45 |
|
||||
46 | mpatch-oss-fuzz.o: ../../mercurial/mpatch.c |
|
41 | mpatch-oss-fuzz.o: ../../mercurial/mpatch.c | |
47 | $(CC) $(CFLAGS) -c -o mpatch-oss-fuzz.o ../../mercurial/mpatch.c |
|
42 | $(CC) $(CFLAGS) -c -o mpatch-oss-fuzz.o ../../mercurial/mpatch.c | |
48 |
|
43 | |||
49 |
mpatch_fuzzer: mpatch.cc mpatch-oss-fuzz.o |
|
44 | mpatch_fuzzer: mpatch.cc mpatch-oss-fuzz.o $$OUT/mpatch_fuzzer_seed_corpus.zip | |
50 | $(CXX) $(CXXFLAGS) -std=c++17 -I../../mercurial mpatch.cc \ |
|
45 | $(CXX) $(CXXFLAGS) -std=c++17 -I../../mercurial mpatch.cc \ | |
51 | mpatch-oss-fuzz.o fuzzutil-oss-fuzz.o -lFuzzingEngine -o \ |
|
46 | mpatch-oss-fuzz.o $(LIB_FUZZING_ENGINE) -o \ | |
52 | $$OUT/mpatch_fuzzer |
|
47 | $$OUT/mpatch_fuzzer | |
53 |
|
48 | |||
54 | mpatch_corpus.zip: |
|
|||
55 | python mpatch_corpus.py $$OUT/mpatch_fuzzer_seed_corpus.zip |
|
|||
56 |
|
||||
57 | x%.o: ../../mercurial/thirdparty/xdiff/x%.c ../../mercurial/thirdparty/xdiff/*.h |
|
|||
58 | $(CC) -g -O1 -fsanitize=fuzzer-no-link,address -c \ |
|
|||
59 | -o $@ \ |
|
|||
60 | $< |
|
|||
61 |
|
||||
62 | xdiff: CXXFLAGS += -std=c++17 |
|
|||
63 | xdiff: xdiff.cc xdiffi.o xprepare.o xutils.o fuzzutil.o |
|
|||
64 | $(CXX) $(CXXFLAGS) -DHG_FUZZER_INCLUDE_MAIN=1 -g -O1 -fsanitize=fuzzer-no-link,address \ |
|
|||
65 | -I../../mercurial xdiff.cc \ |
|
|||
66 | xdiffi.o xprepare.o xutils.o fuzzutil.o -o xdiff |
|
|||
67 |
|
||||
68 | fuzz-x%.o: ../../mercurial/thirdparty/xdiff/x%.c ../../mercurial/thirdparty/xdiff/*.h |
|
49 | fuzz-x%.o: ../../mercurial/thirdparty/xdiff/x%.c ../../mercurial/thirdparty/xdiff/*.h | |
69 | $(CC) $(CFLAGS) -c \ |
|
50 | $(CC) $(CFLAGS) -c \ | |
70 | -o $@ \ |
|
51 | -o $@ \ | |
71 | $< |
|
52 | $< | |
72 |
|
53 | |||
73 |
xdiff_fuzzer: xdiff.cc fuzz-xdiffi.o fuzz-xprepare.o fuzz-xutils.o |
|
54 | xdiff_fuzzer: xdiff.cc fuzz-xdiffi.o fuzz-xprepare.o fuzz-xutils.o | |
74 | $(CXX) $(CXXFLAGS) -std=c++17 -I../../mercurial xdiff.cc \ |
|
55 | $(CXX) $(CXXFLAGS) -std=c++17 -I../../mercurial xdiff.cc \ | |
75 |
fuzz-xdiffi.o fuzz-xprepare.o fuzz-xutils.o |
|
56 | fuzz-xdiffi.o fuzz-xprepare.o fuzz-xutils.o \ | |
76 |
|
|
57 | $(LIB_FUZZING_ENGINE) -o $$OUT/xdiff_fuzzer | |
77 |
|
||||
78 | manifest.o: ../../mercurial/cext/manifest.c |
|
|||
79 | $(CC) $(CFLAGS) `$$OUT/sanpy/bin/python-config --cflags` \ |
|
|||
80 | -I../../mercurial \ |
|
|||
81 | -c -o manifest.o ../../mercurial/cext/manifest.c |
|
|||
82 |
|
||||
83 | charencode.o: ../../mercurial/cext/charencode.c |
|
|||
84 | $(CC) $(CFLAGS) `$$OUT/sanpy/bin/python-config --cflags` \ |
|
|||
85 | -I../../mercurial \ |
|
|||
86 | -c -o charencode.o ../../mercurial/cext/charencode.c |
|
|||
87 |
|
58 | |||
88 |
parsers.o: ../../mercurial/cext/ |
|
59 | parsers-%.o: ../../mercurial/cext/%.c | |
89 | $(CC) $(CFLAGS) `$$OUT/sanpy/bin/python-config --cflags` \ |
|
60 | $(CC) -I../../mercurial `$(PYTHON_CONFIG) --cflags` $(CFLAGS) -c \ | |
90 | -I../../mercurial \ |
|
61 | -o $@ $< | |
91 | -c -o parsers.o ../../mercurial/cext/parsers.c |
|
|||
92 |
|
||||
93 | dirs.o: ../../mercurial/cext/dirs.c |
|
|||
94 | $(CC) $(CFLAGS) `$$OUT/sanpy/bin/python-config --cflags` \ |
|
|||
95 | -I../../mercurial \ |
|
|||
96 | -c -o dirs.o ../../mercurial/cext/dirs.c |
|
|||
97 |
|
62 | |||
98 | pathencode.o: ../../mercurial/cext/pathencode.c |
|
63 | PARSERS_OBJS=parsers-manifest.o parsers-charencode.o parsers-parsers.o parsers-dirs.o parsers-pathencode.o parsers-revlog.o | |
99 | $(CC) $(CFLAGS) `$$OUT/sanpy/bin/python-config --cflags` \ |
|
|||
100 | -I../../mercurial \ |
|
|||
101 | -c -o pathencode.o ../../mercurial/cext/pathencode.c |
|
|||
102 |
|
64 | |||
103 | revlog.o: ../../mercurial/cext/revlog.c |
|
65 | dirs_fuzzer: dirs.cc pyutil.o $(PARSERS_OBJS) $$OUT/dirs_fuzzer_seed_corpus.zip | |
104 | $(CC) $(CFLAGS) `$$OUT/sanpy/bin/python-config --cflags` \ |
|
66 | $(CXX) $(CXXFLAGS) `$(PYTHON_CONFIG) --cflags` \ | |
105 | -I../../mercurial \ |
|
|||
106 | -c -o revlog.o ../../mercurial/cext/revlog.c |
|
|||
107 |
|
||||
108 | dirs_fuzzer: dirs.cc manifest.o charencode.o parsers.o dirs.o pathencode.o revlog.o pyutil.o |
|
|||
109 | $(CXX) $(CXXFLAGS) `$$OUT/sanpy/bin/python-config --cflags` \ |
|
|||
110 | -Wno-register -Wno-macro-redefined \ |
|
67 | -Wno-register -Wno-macro-redefined \ | |
111 | -I../../mercurial dirs.cc \ |
|
68 | -I../../mercurial dirs.cc \ | |
112 | manifest.o charencode.o parsers.o dirs.o pathencode.o revlog.o pyutil.o \ |
|
69 | pyutil.o $(PARSERS_OBJS) \ | |
113 | -lFuzzingEngine `$$OUT/sanpy/bin/python-config --ldflags` \ |
|
70 | $(LIB_FUZZING_ENGINE) `$(PYTHON_CONFIG) --ldflags` \ | |
114 | -o $$OUT/dirs_fuzzer |
|
71 | -o $$OUT/dirs_fuzzer | |
115 |
|
72 | |||
116 | fncache_fuzzer: fncache.cc manifest.o charencode.o parsers.o dirs.o pathencode.o revlog.o pyutil.o |
|
73 | fncache_fuzzer: fncache.cc | |
117 |
$(CXX) $(CXXFLAGS) `$ |
|
74 | $(CXX) $(CXXFLAGS) `$(PYTHON_CONFIG) --cflags` \ | |
118 | -Wno-register -Wno-macro-redefined \ |
|
75 | -Wno-register -Wno-macro-redefined \ | |
119 | -I../../mercurial fncache.cc \ |
|
76 | -I../../mercurial fncache.cc \ | |
120 | manifest.o charencode.o parsers.o dirs.o pathencode.o revlog.o pyutil.o \ |
|
77 | pyutil.o $(PARSERS_OBJS) \ | |
121 | -lFuzzingEngine `$$OUT/sanpy/bin/python-config --ldflags` \ |
|
78 | $(LIB_FUZZING_ENGINE) `$(PYTHON_CONFIG) --ldflags` \ | |
122 | -o $$OUT/fncache_fuzzer |
|
79 | -o $$OUT/fncache_fuzzer | |
123 |
|
80 | |||
124 | jsonescapeu8fast_fuzzer: jsonescapeu8fast.cc manifest.o charencode.o parsers.o dirs.o pathencode.o revlog.o pyutil.o |
|
81 | jsonescapeu8fast_fuzzer: jsonescapeu8fast.cc pyutil.o $(PARSERS_OBJS) | |
125 |
$(CXX) $(CXXFLAGS) `$ |
|
82 | $(CXX) $(CXXFLAGS) `$(PYTHON_CONFIG) --cflags` \ | |
126 | -Wno-register -Wno-macro-redefined \ |
|
83 | -Wno-register -Wno-macro-redefined \ | |
127 | -I../../mercurial jsonescapeu8fast.cc \ |
|
84 | -I../../mercurial jsonescapeu8fast.cc \ | |
128 | manifest.o charencode.o parsers.o dirs.o pathencode.o revlog.o pyutil.o \ |
|
85 | pyutil.o $(PARSERS_OBJS) \ | |
129 | -lFuzzingEngine `$$OUT/sanpy/bin/python-config --ldflags` \ |
|
86 | $(LIB_FUZZING_ENGINE) `$(PYTHON_CONFIG) --ldflags` \ | |
130 | -o $$OUT/jsonescapeu8fast_fuzzer |
|
87 | -o $$OUT/jsonescapeu8fast_fuzzer | |
131 |
|
88 | |||
132 | manifest_corpus.zip: |
|
89 | manifest_fuzzer: manifest.cc pyutil.o $(PARSERS_OBJS) $$OUT/manifest_fuzzer_seed_corpus.zip | |
133 | python manifest_corpus.py $$OUT/manifest_fuzzer_seed_corpus.zip |
|
90 | $(CXX) $(CXXFLAGS) `$(PYTHON_CONFIG) --cflags` \ | |
134 |
|
||||
135 | manifest_fuzzer: manifest.cc manifest.o charencode.o parsers.o dirs.o pathencode.o revlog.o pyutil.o |
|
|||
136 | $(CXX) $(CXXFLAGS) `$$OUT/sanpy/bin/python-config --cflags` \ |
|
|||
137 | -Wno-register -Wno-macro-redefined \ |
|
91 | -Wno-register -Wno-macro-redefined \ | |
138 | -I../../mercurial manifest.cc \ |
|
92 | -I../../mercurial manifest.cc \ | |
139 | manifest.o charencode.o parsers.o dirs.o pathencode.o revlog.o pyutil.o \ |
|
93 | pyutil.o $(PARSERS_OBJS) \ | |
140 | -lFuzzingEngine `$$OUT/sanpy/bin/python-config --ldflags` \ |
|
94 | $(LIB_FUZZING_ENGINE) `$(PYTHON_CONFIG) --ldflags` \ | |
141 | -o $$OUT/manifest_fuzzer |
|
95 | -o $$OUT/manifest_fuzzer | |
142 |
|
96 | |||
143 | revlog_fuzzer: revlog.cc manifest.o charencode.o parsers.o dirs.o pathencode.o revlog.o pyutil.o |
|
97 | revlog_fuzzer: revlog.cc pyutil.o $(PARSERS_OBJS) $$OUT/revlog_fuzzer_seed_corpus.zip | |
144 |
$(CXX) $(CXXFLAGS) `$ |
|
98 | $(CXX) $(CXXFLAGS) `$(PYTHON_CONFIG) --cflags` \ | |
145 | -Wno-register -Wno-macro-redefined \ |
|
99 | -Wno-register -Wno-macro-redefined \ | |
146 | -I../../mercurial revlog.cc \ |
|
100 | -I../../mercurial revlog.cc \ | |
147 | manifest.o charencode.o parsers.o dirs.o pathencode.o revlog.o pyutil.o \ |
|
101 | pyutil.o $(PARSERS_OBJS) \ | |
148 | -lFuzzingEngine `$$OUT/sanpy/bin/python-config --ldflags` \ |
|
102 | $(LIB_FUZZING_ENGINE) `$(PYTHON_CONFIG) --ldflags` \ | |
149 | -o $$OUT/revlog_fuzzer |
|
103 | -o $$OUT/revlog_fuzzer | |
150 |
|
104 | |||
151 | revlog_corpus.zip: |
|
105 | dirstate_fuzzer: dirstate.cc pyutil.o $(PARSERS_OBJS) $$OUT/dirstate_fuzzer_seed_corpus.zip | |
152 | python revlog_corpus.py $$OUT/revlog_fuzzer_seed_corpus.zip |
|
106 | $(CXX) $(CXXFLAGS) `$(PYTHON_CONFIG) --cflags` \ | |
153 |
|
||||
154 | dirstate_fuzzer: dirstate.cc manifest.o charencode.o parsers.o dirs.o pathencode.o revlog.o pyutil.o |
|
|||
155 | $(CXX) $(CXXFLAGS) `$$OUT/sanpy/bin/python-config --cflags` \ |
|
|||
156 | -Wno-register -Wno-macro-redefined \ |
|
107 | -Wno-register -Wno-macro-redefined \ | |
157 | -I../../mercurial dirstate.cc \ |
|
108 | -I../../mercurial dirstate.cc \ | |
158 | manifest.o charencode.o parsers.o dirs.o pathencode.o revlog.o pyutil.o \ |
|
109 | pyutil.o $(PARSERS_OBJS) \ | |
159 | -lFuzzingEngine `$$OUT/sanpy/bin/python-config --ldflags` \ |
|
110 | $(LIB_FUZZING_ENGINE) `$(PYTHON_CONFIG) --ldflags` \ | |
160 | -o $$OUT/dirstate_fuzzer |
|
111 | -o $$OUT/dirstate_fuzzer | |
161 |
|
112 | |||
162 | dirstate_corpus.zip: |
|
113 | fm1readmarkers_fuzzer: fm1readmarkers.cc pyutil.o $(PARSERS_OBJS) $$OUT/fm1readmarkers_fuzzer_seed_corpus.zip | |
163 | python dirstate_corpus.py $$OUT/dirstate_fuzzer_seed_corpus.zip |
|
114 | $(CXX) $(CXXFLAGS) `$(PYTHON_CONFIG) --cflags` \ | |
164 |
|
||||
165 | fm1readmarkers_fuzzer: fm1readmarkers.cc manifest.o charencode.o parsers.o dirs.o pathencode.o revlog.o pyutil.o |
|
|||
166 | $(CXX) $(CXXFLAGS) `$$OUT/sanpy/bin/python-config --cflags` \ |
|
|||
167 | -Wno-register -Wno-macro-redefined \ |
|
115 | -Wno-register -Wno-macro-redefined \ | |
168 | -I../../mercurial fm1readmarkers.cc \ |
|
116 | -I../../mercurial fm1readmarkers.cc \ | |
169 | manifest.o charencode.o parsers.o dirs.o pathencode.o revlog.o pyutil.o \ |
|
117 | pyutil.o $(PARSERS_OBJS) \ | |
170 | -lFuzzingEngine `$$OUT/sanpy/bin/python-config --ldflags` \ |
|
118 | $(LIB_FUZZING_ENGINE) `$(PYTHON_CONFIG) --ldflags` \ | |
171 | -o $$OUT/fm1readmarkers_fuzzer |
|
119 | -o $$OUT/fm1readmarkers_fuzzer | |
172 |
|
120 | |||
173 | fm1readmarkers_corpus.zip: |
|
|||
174 | python fm1readmarkers_corpus.py $$OUT/fm1readmarkers_fuzzer_seed_corpus.zip |
|
|||
175 |
|
||||
176 | clean: |
|
121 | clean: | |
177 | $(RM) *.o *_fuzzer \ |
|
122 | $(RM) *.o *_fuzzer \ | |
178 | bdiff \ |
|
123 | bdiff \ | |
179 | mpatch \ |
|
124 | mpatch \ | |
180 | xdiff |
|
125 | xdiff | |
181 |
|
126 | |||
182 |
oss-fuzz: bdiff_fuzzer mpatch_fuzzer |
|
127 | oss-fuzz: bdiff_fuzzer mpatch_fuzzer xdiff_fuzzer dirs_fuzzer fncache_fuzzer jsonescapeu8fast_fuzzer manifest_fuzzer revlog_fuzzer dirstate_fuzzer fm1readmarkers_fuzzer | |
183 |
|
128 | |||
184 | .PHONY: all clean oss-fuzz |
|
129 | .PHONY: all clean oss-fuzz |
@@ -9,22 +9,25 b'' | |||||
9 | #include <memory> |
|
9 | #include <memory> | |
10 | #include <stdlib.h> |
|
10 | #include <stdlib.h> | |
11 |
|
11 | |||
12 |
#include " |
|
12 | #include "FuzzedDataProvider.h" | |
13 |
|
13 | |||
14 | extern "C" { |
|
14 | extern "C" { | |
15 | #include "bdiff.h" |
|
15 | #include "bdiff.h" | |
16 |
|
16 | |||
|
17 | extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) | |||
|
18 | { | |||
|
19 | return 0; | |||
|
20 | } | |||
|
21 | ||||
17 | int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) |
|
22 | int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) | |
18 | { |
|
23 | { | |
19 | auto maybe_inputs = SplitInputs(Data, Size); |
|
24 | FuzzedDataProvider provider(Data, Size); | |
20 | if (!maybe_inputs) { |
|
25 | std::string left = provider.ConsumeRandomLengthString(Size); | |
21 | return 0; |
|
26 | std::string right = provider.ConsumeRemainingBytesAsString(); | |
22 | } |
|
|||
23 | auto inputs = std::move(maybe_inputs.value()); |
|
|||
24 |
|
27 | |||
25 | struct bdiff_line *a, *b; |
|
28 | struct bdiff_line *a, *b; | |
26 |
int an = bdiff_splitlines( |
|
29 | int an = bdiff_splitlines(left.c_str(), left.size(), &a); | |
27 |
int bn = bdiff_splitlines( |
|
30 | int bn = bdiff_splitlines(right.c_str(), right.size(), &b); | |
28 | struct bdiff_hunk l; |
|
31 | struct bdiff_hunk l; | |
29 | bdiff_diff(a, an, b, bn, &l); |
|
32 | bdiff_diff(a, an, b, bn, &l); | |
30 | free(a); |
|
33 | free(a); | |
@@ -33,12 +36,4 b' int LLVMFuzzerTestOneInput(const uint8_t' | |||||
33 | return 0; // Non-zero return values are reserved for future use. |
|
36 | return 0; // Non-zero return values are reserved for future use. | |
34 | } |
|
37 | } | |
35 |
|
38 | |||
36 | #ifdef HG_FUZZER_INCLUDE_MAIN |
|
|||
37 | int main(int argc, char **argv) |
|
|||
38 | { |
|
|||
39 | const char data[] = "asdf"; |
|
|||
40 | return LLVMFuzzerTestOneInput((const uint8_t *)data, 4); |
|
|||
41 | } |
|
|||
42 | #endif |
|
|||
43 |
|
||||
44 | } // extern "C" |
|
39 | } // extern "C" |
@@ -9,16 +9,15 b'' | |||||
9 |
|
9 | |||
10 | extern "C" { |
|
10 | extern "C" { | |
11 |
|
11 | |||
12 |
static P |
|
12 | static PYCODETYPE *code; | |
13 |
|
13 | |||
14 | extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) |
|
14 | extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) | |
15 | { |
|
15 | { | |
16 | contrib::initpy(*argv[0]); |
|
16 | contrib::initpy(*argv[0]); | |
17 |
code = (P |
|
17 | code = (PYCODETYPE *)Py_CompileString(R"py( | |
18 | from parsers import dirs |
|
|||
19 | try: |
|
18 | try: | |
20 | files = mdata.split('\n') |
|
19 | files = mdata.split('\n') | |
21 | d = dirs(files) |
|
20 | d = parsers.dirs(files) | |
22 | list(d) |
|
21 | list(d) | |
23 | 'a' in d |
|
22 | 'a' in d | |
24 | if files: |
|
23 | if files: | |
@@ -29,7 +28,7 b' except Exception as e:' | |||||
29 | # to debug failures. |
|
28 | # to debug failures. | |
30 | # print e |
|
29 | # print e | |
31 | )py", |
|
30 | )py", | |
32 |
|
|
31 | "fuzzer", Py_file_input); | |
33 | return 0; |
|
32 | return 0; | |
34 | } |
|
33 | } | |
35 |
|
34 |
@@ -9,24 +9,23 b'' | |||||
9 |
|
9 | |||
10 | extern "C" { |
|
10 | extern "C" { | |
11 |
|
11 | |||
12 |
static P |
|
12 | static PYCODETYPE *code; | |
13 |
|
13 | |||
14 | extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) |
|
14 | extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) | |
15 | { |
|
15 | { | |
16 | contrib::initpy(*argv[0]); |
|
16 | contrib::initpy(*argv[0]); | |
17 |
code = (P |
|
17 | code = (PYCODETYPE *)Py_CompileString(R"py( | |
18 | from parsers import parse_dirstate |
|
|||
19 | try: |
|
18 | try: | |
20 | dmap = {} |
|
19 | dmap = {} | |
21 | copymap = {} |
|
20 | copymap = {} | |
22 | p = parse_dirstate(dmap, copymap, data) |
|
21 | p = parsers.parse_dirstate(dmap, copymap, data) | |
23 | except Exception as e: |
|
22 | except Exception as e: | |
24 | pass |
|
23 | pass | |
25 | # uncomment this print if you're editing this Python code |
|
24 | # uncomment this print if you're editing this Python code | |
26 | # to debug failures. |
|
25 | # to debug failures. | |
27 | # print e |
|
26 | # print e | |
28 | )py", |
|
27 | )py", | |
29 |
|
|
28 | "fuzzer", Py_file_input); | |
30 | return 0; |
|
29 | return 0; | |
31 | } |
|
30 | } | |
32 |
|
31 |
@@ -13,5 +13,5 b" dirstate = os.path.join(reporoot, '.hg'," | |||||
13 |
|
13 | |||
14 | with zipfile.ZipFile(args.out[0], "w", zipfile.ZIP_STORED) as zf: |
|
14 | with zipfile.ZipFile(args.out[0], "w", zipfile.ZIP_STORED) as zf: | |
15 | if os.path.exists(dirstate): |
|
15 | if os.path.exists(dirstate): | |
16 | with open(dirstate) as f: |
|
16 | with open(dirstate, 'rb') as f: | |
17 | zf.writestr("dirstate", f.read()) |
|
17 | zf.writestr("dirstate", f.read()) |
@@ -9,13 +9,12 b'' | |||||
9 |
|
9 | |||
10 | extern "C" { |
|
10 | extern "C" { | |
11 |
|
11 | |||
12 |
static P |
|
12 | static PYCODETYPE *code; | |
13 |
|
13 | |||
14 | extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) |
|
14 | extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) | |
15 | { |
|
15 | { | |
16 | contrib::initpy(*argv[0]); |
|
16 | contrib::initpy(*argv[0]); | |
17 |
code = (P |
|
17 | code = (PYCODETYPE *)Py_CompileString(R"py( | |
18 | from parsers import fm1readmarkers |
|
|||
19 | def maybeint(s, default): |
|
18 | def maybeint(s, default): | |
20 | try: |
|
19 | try: | |
21 | return int(s) |
|
20 | return int(s) | |
@@ -31,14 +30,14 b' try:' | |||||
31 | else: |
|
30 | else: | |
32 | offset = stop = 0 |
|
31 | offset = stop = 0 | |
33 | offset, stop = maybeint(offset, 0), maybeint(stop, len(data)) |
|
32 | offset, stop = maybeint(offset, 0), maybeint(stop, len(data)) | |
34 | fm1readmarkers(data, offset, stop) |
|
33 | parsers.fm1readmarkers(data, offset, stop) | |
35 | except Exception as e: |
|
34 | except Exception as e: | |
36 | pass |
|
35 | pass | |
37 | # uncomment this print if you're editing this Python code |
|
36 | # uncomment this print if you're editing this Python code | |
38 | # to debug failures. |
|
37 | # to debug failures. | |
39 | # print e |
|
38 | # print e | |
40 | )py", |
|
39 | )py", | |
41 |
|
|
40 | "fuzzer", Py_file_input); | |
42 | return 0; |
|
41 | return 0; | |
43 | } |
|
42 | } | |
44 |
|
43 |
@@ -10,29 +10,20 b'' | |||||
10 |
|
10 | |||
11 | extern "C" { |
|
11 | extern "C" { | |
12 |
|
12 | |||
13 |
static P |
|
13 | static PYCODETYPE *code; | |
14 |
|
14 | |||
15 | extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) |
|
15 | extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) | |
16 | { |
|
16 | { | |
17 | contrib::initpy(*argv[0]); |
|
17 | contrib::initpy(*argv[0]); | |
18 |
code = (P |
|
18 | code = (PYCODETYPE *)Py_CompileString(R"py( | |
19 | from parsers import ( |
|
|||
20 | isasciistr, |
|
|||
21 | asciilower, |
|
|||
22 | asciiupper, |
|
|||
23 | encodedir, |
|
|||
24 | pathencode, |
|
|||
25 | lowerencode, |
|
|||
26 | ) |
|
|||
27 |
|
||||
28 | try: |
|
19 | try: | |
29 | for fn in ( |
|
20 | for fn in ( | |
30 | isasciistr, |
|
21 | parsers.isasciistr, | |
31 | asciilower, |
|
22 | parsers.asciilower, | |
32 | asciiupper, |
|
23 | parsers.asciiupper, | |
33 | encodedir, |
|
24 | parsers.encodedir, | |
34 | pathencode, |
|
25 | parsers.pathencode, | |
35 | lowerencode, |
|
26 | parsers.lowerencode, | |
36 | ): |
|
27 | ): | |
37 | try: |
|
28 | try: | |
38 | fn(data) |
|
29 | fn(data) | |
@@ -53,7 +44,7 b' except Exception as e:' | |||||
53 | # to debug failures. |
|
44 | # to debug failures. | |
54 | # print(e) |
|
45 | # print(e) | |
55 | )py", |
|
46 | )py", | |
56 |
|
|
47 | "fuzzer", Py_file_input); | |
57 | if (!code) { |
|
48 | if (!code) { | |
58 | std::cerr << "failed to compile Python code!" << std::endl; |
|
49 | std::cerr << "failed to compile Python code!" << std::endl; | |
59 | } |
|
50 | } |
@@ -34,14 +34,4 b' using absl::optional;' | |||||
34 | if (level <= DEBUG) \ |
|
34 | if (level <= DEBUG) \ | |
35 | std::cout |
|
35 | std::cout | |
36 |
|
36 | |||
37 | struct two_inputs { |
|
|||
38 | std::unique_ptr<char[]> right; |
|
|||
39 | size_t right_size; |
|
|||
40 | std::unique_ptr<char[]> left; |
|
|||
41 | size_t left_size; |
|
|||
42 | }; |
|
|||
43 |
|
||||
44 | /* Split a non-zero-length input into two inputs. */ |
|
|||
45 | contrib::optional<two_inputs> SplitInputs(const uint8_t *Data, size_t Size); |
|
|||
46 |
|
||||
47 | #endif /* CONTRIB_FUZZ_FUZZUTIL_H */ |
|
37 | #endif /* CONTRIB_FUZZ_FUZZUTIL_H */ |
@@ -5,29 +5,27 b'' | |||||
5 |
|
5 | |||
6 | #include "pyutil.h" |
|
6 | #include "pyutil.h" | |
7 |
|
7 | |||
8 | #include <fuzzer/FuzzedDataProvider.h> |
|
|||
9 | #include <iostream> |
|
8 | #include <iostream> | |
10 | #include <string> |
|
9 | #include <string> | |
|
10 | #include "FuzzedDataProvider.h" | |||
11 |
|
11 | |||
12 | extern "C" { |
|
12 | extern "C" { | |
13 |
|
13 | |||
14 |
static P |
|
14 | static PYCODETYPE *code; | |
15 |
|
15 | |||
16 | extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) |
|
16 | extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) | |
17 | { |
|
17 | { | |
18 | contrib::initpy(*argv[0]); |
|
18 | contrib::initpy(*argv[0]); | |
19 |
code = (P |
|
19 | code = (PYCODETYPE *)Py_CompileString(R"py( | |
20 | from parsers import jsonescapeu8fast |
|
|||
21 |
|
||||
22 | try: |
|
20 | try: | |
23 | jsonescapeu8fast(data, paranoid) |
|
21 | parsers.jsonescapeu8fast(data, paranoid) | |
24 | except Exception as e: |
|
22 | except Exception as e: | |
25 | pass |
|
23 | pass | |
26 | # uncomment this print if you're editing this Python code |
|
24 | # uncomment this print if you're editing this Python code | |
27 | # to debug failures. |
|
25 | # to debug failures. | |
28 | # print(e) |
|
26 | # print(e) | |
29 | )py", |
|
27 | )py", | |
30 |
|
|
28 | "fuzzer", Py_file_input); | |
31 | if (!code) { |
|
29 | if (!code) { | |
32 | std::cerr << "failed to compile Python code!" << std::endl; |
|
30 | std::cerr << "failed to compile Python code!" << std::endl; | |
33 | } |
|
31 | } |
@@ -9,15 +9,14 b'' | |||||
9 |
|
9 | |||
10 | extern "C" { |
|
10 | extern "C" { | |
11 |
|
11 | |||
12 |
static P |
|
12 | static PYCODETYPE *code; | |
13 |
|
13 | |||
14 | extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) |
|
14 | extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) | |
15 | { |
|
15 | { | |
16 | contrib::initpy(*argv[0]); |
|
16 | contrib::initpy(*argv[0]); | |
17 |
code = (P |
|
17 | code = (PYCODETYPE *)Py_CompileString(R"py( | |
18 | from parsers import lazymanifest |
|
|||
19 | try: |
|
18 | try: | |
20 | lm = lazymanifest(mdata) |
|
19 | lm = parsers.lazymanifest(mdata) | |
21 | # iterate the whole thing, which causes the code to fully parse |
|
20 | # iterate the whole thing, which causes the code to fully parse | |
22 | # every line in the manifest |
|
21 | # every line in the manifest | |
23 | for e, _, _ in lm.iterentries(): |
|
22 | for e, _, _ in lm.iterentries(): | |
@@ -41,7 +40,7 b' except Exception as e:' | |||||
41 | # to debug failures. |
|
40 | # to debug failures. | |
42 | # print e |
|
41 | # print e | |
43 | )py", |
|
42 | )py", | |
44 |
|
|
43 | "fuzzer", Py_file_input); | |
45 | return 0; |
|
44 | return 0; | |
46 | } |
|
45 | } | |
47 |
|
46 |
@@ -14,6 +14,11 b'' | |||||
14 |
|
14 | |||
15 | #include "fuzzutil.h" |
|
15 | #include "fuzzutil.h" | |
16 |
|
16 | |||
|
17 | extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) | |||
|
18 | { | |||
|
19 | return 0; | |||
|
20 | } | |||
|
21 | ||||
17 | // To avoid having too many OOMs from the fuzzer infrastructure, we'll |
|
22 | // To avoid having too many OOMs from the fuzzer infrastructure, we'll | |
18 | // skip patch application if the resulting fulltext would be bigger |
|
23 | // skip patch application if the resulting fulltext would be bigger | |
19 | // than 10MiB. |
|
24 | // than 10MiB. | |
@@ -106,17 +111,4 b' cleanup:' | |||||
106 | return 0; |
|
111 | return 0; | |
107 | } |
|
112 | } | |
108 |
|
113 | |||
109 | #ifdef HG_FUZZER_INCLUDE_MAIN |
|
|||
110 | int main(int argc, char **argv) |
|
|||
111 | { |
|
|||
112 | // One text, one patch. |
|
|||
113 | const char data[] = "\x02\x00\0x1\x00\x0d" |
|
|||
114 | // base text |
|
|||
115 | "a" |
|
|||
116 | // binary delta that will append a single b |
|
|||
117 | "\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01b"; |
|
|||
118 | return LLVMFuzzerTestOneInput((const uint8_t *)data, 19); |
|
|||
119 | } |
|
|||
120 | #endif |
|
|||
121 |
|
||||
122 | } // extern "C" |
|
114 | } // extern "C" |
This diff has been collapsed as it changes many lines, (568 lines changed) Show them Hide them | |||||
@@ -2,6 +2,7 b' from __future__ import absolute_import, ' | |||||
2 |
|
2 | |||
3 | import argparse |
|
3 | import argparse | |
4 | import struct |
|
4 | import struct | |
|
5 | import sys | |||
5 | import zipfile |
|
6 | import zipfile | |
6 |
|
7 | |||
7 | from mercurial import ( |
|
8 | from mercurial import ( | |
@@ -14,34 +15,48 b' ap.add_argument("out", metavar="some.zip' | |||||
14 | args = ap.parse_args() |
|
15 | args = ap.parse_args() | |
15 |
|
16 | |||
16 |
|
17 | |||
17 | class deltafrag(object): |
|
18 | if sys.version_info[0] < 3: | |
|
19 | ||||
|
20 | class py2reprhack(object): | |||
|
21 | def __repr__(self): | |||
|
22 | """Py2 calls __repr__ for `bytes(foo)`, forward to __bytes__""" | |||
|
23 | return self.__bytes__() | |||
|
24 | ||||
|
25 | ||||
|
26 | else: | |||
|
27 | ||||
|
28 | class py2reprhack(object): | |||
|
29 | """Not needed on py3.""" | |||
|
30 | ||||
|
31 | ||||
|
32 | class deltafrag(py2reprhack): | |||
18 | def __init__(self, start, end, data): |
|
33 | def __init__(self, start, end, data): | |
19 | self.start = start |
|
34 | self.start = start | |
20 | self.end = end |
|
35 | self.end = end | |
21 | self.data = data |
|
36 | self.data = data | |
22 |
|
37 | |||
23 |
def __ |
|
38 | def __bytes__(self): | |
24 | return ( |
|
39 | return ( | |
25 | struct.pack(">lll", self.start, self.end, len(self.data)) |
|
40 | struct.pack(">lll", self.start, self.end, len(self.data)) | |
26 | + self.data |
|
41 | + self.data | |
27 | ) |
|
42 | ) | |
28 |
|
43 | |||
29 |
|
44 | |||
30 |
class delta( |
|
45 | class delta(py2reprhack): | |
31 | def __init__(self, frags): |
|
46 | def __init__(self, frags): | |
32 | self.frags = frags |
|
47 | self.frags = frags | |
33 |
|
48 | |||
34 |
def __ |
|
49 | def __bytes__(self): | |
35 |
return ''.join( |
|
50 | return b''.join(bytes(f) for f in self.frags) | |
36 |
|
51 | |||
37 |
|
52 | |||
38 |
class corpus( |
|
53 | class corpus(py2reprhack): | |
39 | def __init__(self, base, deltas): |
|
54 | def __init__(self, base, deltas): | |
40 | self.base = base |
|
55 | self.base = base | |
41 | self.deltas = deltas |
|
56 | self.deltas = deltas | |
42 |
|
57 | |||
43 |
def __ |
|
58 | def __bytes__(self): | |
44 |
deltas = [ |
|
59 | deltas = [bytes(d) for d in self.deltas] | |
45 | parts = ( |
|
60 | parts = ( | |
46 | [ |
|
61 | [ | |
47 | struct.pack(">B", len(deltas) + 1), |
|
62 | struct.pack(">B", len(deltas) + 1), | |
@@ -51,300 +66,301 b' class corpus(object):' | |||||
51 | + [self.base] |
|
66 | + [self.base] | |
52 | + deltas |
|
67 | + deltas | |
53 | ) |
|
68 | ) | |
54 |
return |
|
69 | return b''.join(parts) | |
55 |
|
70 | |||
56 |
|
71 | |||
57 | with zipfile.ZipFile(args.out[0], "w", zipfile.ZIP_STORED) as zf: |
|
72 | with zipfile.ZipFile(args.out[0], "w", zipfile.ZIP_STORED) as zf: | |
58 | # Manually constructed entries |
|
73 | # Manually constructed entries | |
59 | zf.writestr( |
|
74 | zf.writestr( | |
60 | "one_delta_applies", str(corpus('a', [delta([deltafrag(0, 1, 'b')])])) |
|
75 | "one_delta_applies", | |
|
76 | bytes(corpus(b'a', [delta([deltafrag(0, 1, b'b')])])), | |||
61 | ) |
|
77 | ) | |
62 | zf.writestr( |
|
78 | zf.writestr( | |
63 | "one_delta_starts_late", |
|
79 | "one_delta_starts_late", | |
64 |
|
|
80 | bytes(corpus(b'a', [delta([deltafrag(3, 1, b'b')])])), | |
65 | ) |
|
81 | ) | |
66 | zf.writestr( |
|
82 | zf.writestr( | |
67 | "one_delta_ends_late", |
|
83 | "one_delta_ends_late", | |
68 |
|
|
84 | bytes(corpus(b'a', [delta([deltafrag(0, 20, b'b')])])), | |
69 | ) |
|
85 | ) | |
70 |
|
86 | |||
71 | try: |
|
87 | try: | |
72 | # Generated from repo data |
|
88 | # Generated from repo data | |
73 | r = hg.repository(uimod.ui(), '../..') |
|
89 | r = hg.repository(uimod.ui(), b'../..') | |
74 | fl = r.file('mercurial/manifest.py') |
|
90 | fl = r.file(b'mercurial/manifest.py') | |
75 | rl = getattr(fl, '_revlog', fl) |
|
91 | rl = getattr(fl, '_revlog', fl) | |
76 | bins = rl._chunks(rl._deltachain(10)[0]) |
|
92 | bins = rl._chunks(rl._deltachain(10)[0]) | |
77 |
zf.writestr('manifest_py_rev_10', |
|
93 | zf.writestr('manifest_py_rev_10', bytes(corpus(bins[0], bins[1:]))) | |
78 | except: # skip this, so no re-raises |
|
94 | except: # skip this, so no re-raises | |
79 | print('skipping seed file from repo data') |
|
95 | print('skipping seed file from repo data') | |
80 | # Automatically discovered by running the fuzzer |
|
96 | # Automatically discovered by running the fuzzer | |
81 | zf.writestr( |
|
97 | zf.writestr( | |
82 | "mpatch_decode_old_overread", "\x02\x00\x00\x00\x02\x00\x00\x00" |
|
98 | "mpatch_decode_old_overread", b"\x02\x00\x00\x00\x02\x00\x00\x00" | |
83 | ) |
|
99 | ) | |
84 | # https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=8876 |
|
100 | # https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=8876 | |
85 | zf.writestr( |
|
101 | zf.writestr( | |
86 | "mpatch_ossfuzz_getbe32_ubsan", |
|
102 | "mpatch_ossfuzz_getbe32_ubsan", | |
87 | "\x02\x00\x00\x00\x0c \xff\xff\xff\xff ", |
|
103 | b"\x02\x00\x00\x00\x0c \xff\xff\xff\xff ", | |
88 | ) |
|
104 | ) | |
89 | zf.writestr( |
|
105 | zf.writestr( | |
90 | "mpatch_apply_over_memcpy", |
|
106 | "mpatch_apply_over_memcpy", | |
91 | '\x13\x01\x00\x05\xd0\x00\x00\x00\x00\x00\x00\x00\x00\n \x00\x00\x00' |
|
107 | b'\x13\x01\x00\x05\xd0\x00\x00\x00\x00\x00\x00\x00\x00\n \x00\x00\x00' | |
92 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
108 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
93 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00\x00' |
|
109 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00\x00' | |
94 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
110 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
95 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
111 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
96 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
112 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
97 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
113 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
98 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
114 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
99 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
115 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
100 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
116 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
101 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
117 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
102 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
118 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
103 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
119 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
104 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
120 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
105 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
121 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
106 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
122 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
107 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
123 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
108 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
124 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
109 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
125 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
110 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
126 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
111 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
127 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
112 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
128 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
113 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
129 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
114 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
130 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
115 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
131 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
116 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
132 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
117 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
133 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
118 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
134 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
119 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
135 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
120 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
136 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
121 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8c\x00\x00\x00\x00' |
|
137 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8c\x00\x00\x00\x00' | |
122 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
138 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
123 | '\x00\x00\x00\x00\x00\x00\x00\x00)\x00\x00\x00\x00\x00\x00\x00\x00' |
|
139 | b'\x00\x00\x00\x00\x00\x00\x00\x00)\x00\x00\x00\x00\x00\x00\x00\x00' | |
124 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
140 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
125 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
141 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
126 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
142 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
127 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
143 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
128 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
144 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
129 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
145 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
130 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
146 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
131 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
147 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
132 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
148 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
133 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
149 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
134 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
150 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
135 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
151 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
136 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
152 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
137 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
153 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
138 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
154 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
139 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
155 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
140 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
156 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
141 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
157 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
142 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
158 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
143 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
159 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
144 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
160 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
145 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
161 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
146 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
162 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
147 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
163 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
148 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
164 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
149 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
165 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
150 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
166 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
151 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
167 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
152 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
168 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
153 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
169 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
154 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
170 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
155 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
171 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
156 | '\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00A\x00\x00\x00\x00' |
|
172 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00A\x00\x00\x00\x00' | |
157 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
173 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
158 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
174 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
159 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
175 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
160 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
176 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
161 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
177 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
162 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
178 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
163 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
179 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
164 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
180 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
165 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
181 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
166 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
182 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
167 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
183 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
168 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
184 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
169 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
185 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
170 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
186 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
171 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
187 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
172 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
188 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
173 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
189 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
174 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
190 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
175 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
191 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
176 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
192 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
177 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
193 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
178 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
194 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
179 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
195 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
180 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
196 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
181 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x94\x18' |
|
197 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x94\x18' | |
182 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
198 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
183 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
199 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
184 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
200 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
185 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
201 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
186 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
202 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
187 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
203 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
188 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
204 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
189 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
205 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
190 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
206 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
191 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
207 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
192 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
208 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
193 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
209 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
194 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
210 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
195 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
211 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
196 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
212 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
197 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
213 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
198 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
214 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
199 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
215 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
200 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
216 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
201 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
217 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
202 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
218 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
203 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
219 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
204 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
220 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
205 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
221 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
206 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
222 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
207 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
223 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
208 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
224 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
209 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
225 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
210 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
226 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
211 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
227 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
212 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
228 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
213 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
229 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
214 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
230 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
215 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
231 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
216 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
232 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
217 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
233 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
218 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
234 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
219 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
235 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
220 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
236 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
221 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
237 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
222 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
238 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
223 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
239 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
224 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
240 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
225 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
241 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
226 | '\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
242 | b'\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
227 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
243 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
228 | '\x00\x00\x00\x00\x00\x00\x00\x00\xff\xfa\x00\x00\x00\x00\x00\x00\x00' |
|
244 | b'\x00\x00\x00\x00\x00\x00\x00\x00\xff\xfa\x00\x00\x00\x00\x00\x00\x00' | |
229 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
245 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
230 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
246 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
231 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
247 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
232 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
248 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
233 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
249 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
234 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
250 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
235 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
251 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
236 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
252 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
237 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
253 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
238 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
254 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
239 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
255 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
240 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
256 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
241 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
257 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
242 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
258 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
243 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
259 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
244 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
260 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
245 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
261 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
246 | '\x00\x00\x94\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
262 | b'\x00\x00\x94\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
247 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
263 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
248 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
264 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
249 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
265 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
250 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
266 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
251 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
267 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
252 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
268 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
253 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
269 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
254 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
270 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
255 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
271 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
256 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
272 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
257 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
273 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
258 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
274 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
259 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
275 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
260 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
276 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
261 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
277 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
262 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
278 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
263 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
279 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
264 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
280 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
265 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
281 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
266 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
282 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
267 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
283 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
268 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
284 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
269 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
285 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
270 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
286 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
271 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
287 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
272 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
288 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
273 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
289 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
274 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
290 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
275 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
291 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
276 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
292 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
277 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
293 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
278 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
294 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
279 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
295 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
280 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
296 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
281 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
297 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
282 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
298 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
283 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
299 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
284 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
300 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
285 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
301 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
286 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
302 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
287 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
303 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
288 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
304 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
289 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
305 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
290 | '\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
306 | b'\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
291 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
307 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
292 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xfa\x00\x00\x00' |
|
308 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xfa\x00\x00\x00' | |
293 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
309 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
294 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
310 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
295 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
311 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
296 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
312 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
297 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
313 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
298 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
314 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
299 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
315 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
300 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
316 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
301 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
317 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
302 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
318 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
303 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
319 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
304 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
320 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
305 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
321 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
306 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
322 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
307 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
323 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
308 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
324 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
309 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
325 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
310 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
326 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
311 | '\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00' |
|
327 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00' | |
312 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
328 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
313 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
329 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
314 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
330 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
315 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
331 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
316 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
332 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
317 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
333 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
318 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
334 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
319 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
335 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
320 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
336 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
321 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
337 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
322 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
338 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
323 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
339 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
324 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
340 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
325 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
341 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
326 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x00\x00\x00\x00\x00\x00' |
|
342 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x00\x00\x00\x00\x00\x00' | |
327 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
343 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
328 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
344 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
329 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
345 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
330 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
346 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
331 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\x00\x00' |
|
347 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\x00\x00' | |
332 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
348 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
333 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
349 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
334 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
350 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
335 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
351 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
336 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
352 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
337 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
353 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
338 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
354 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
339 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
355 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
340 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
356 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
341 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
357 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
342 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
358 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
343 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
359 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
344 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
360 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
345 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
361 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
346 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
362 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
347 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00se\x00\x00' |
|
363 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00se\x00\x00' | |
348 | '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
364 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | |
349 | '\x00\x00\x00\x00', |
|
365 | b'\x00\x00\x00\x00', | |
350 | ) |
|
366 | ) |
@@ -1,21 +1,31 b'' | |||||
1 | #include "pyutil.h" |
|
1 | #include "pyutil.h" | |
2 |
|
2 | |||
|
3 | #include <iostream> | |||
3 | #include <string> |
|
4 | #include <string> | |
4 |
|
5 | |||
5 | namespace contrib |
|
6 | namespace contrib | |
6 | { |
|
7 | { | |
7 |
|
8 | |||
|
9 | #if PY_MAJOR_VERSION >= 3 | |||
|
10 | #define HG_FUZZER_PY3 1 | |||
|
11 | PyMODINIT_FUNC PyInit_parsers(void); | |||
|
12 | #else | |||
|
13 | PyMODINIT_FUNC initparsers(void); | |||
|
14 | #endif | |||
|
15 | ||||
8 | static char cpypath[8192] = "\0"; |
|
16 | static char cpypath[8192] = "\0"; | |
9 |
|
17 | |||
10 | static PyObject *mainmod; |
|
18 | static PyObject *mainmod; | |
11 | static PyObject *globals; |
|
19 | static PyObject *globals; | |
12 |
|
20 | |||
13 | /* TODO: use Python 3 for this fuzzing? */ |
|
|||
14 | PyMODINIT_FUNC initparsers(void); |
|
|||
15 |
|
||||
16 | void initpy(const char *cselfpath) |
|
21 | void initpy(const char *cselfpath) | |
17 | { |
|
22 | { | |
|
23 | #ifdef HG_FUZZER_PY3 | |||
|
24 | const std::string subdir = "/sanpy/lib/python3.7"; | |||
|
25 | #else | |||
18 | const std::string subdir = "/sanpy/lib/python2.7"; |
|
26 | const std::string subdir = "/sanpy/lib/python2.7"; | |
|
27 | #endif | |||
|
28 | ||||
19 | /* HACK ALERT: we need a full Python installation built without |
|
29 | /* HACK ALERT: we need a full Python installation built without | |
20 | pymalloc and with ASAN, so we dump one in |
|
30 | pymalloc and with ASAN, so we dump one in | |
21 | $OUT/sanpy/lib/python2.7. This helps us wire that up. */ |
|
31 | $OUT/sanpy/lib/python2.7. This helps us wire that up. */ | |
@@ -24,7 +34,11 b' void initpy(const char *cselfpath)' | |||||
24 | auto pos = selfpath.rfind("/"); |
|
34 | auto pos = selfpath.rfind("/"); | |
25 | if (pos == std::string::npos) { |
|
35 | if (pos == std::string::npos) { | |
26 | char wd[8192]; |
|
36 | char wd[8192]; | |
27 |
getcwd(wd, 8192) |
|
37 | if (!getcwd(wd, 8192)) { | |
|
38 | std::cerr << "Failed to call getcwd: errno " << errno | |||
|
39 | << std::endl; | |||
|
40 | exit(1); | |||
|
41 | } | |||
28 | pypath = std::string(wd) + subdir; |
|
42 | pypath = std::string(wd) + subdir; | |
29 | } else { |
|
43 | } else { | |
30 | pypath = selfpath.substr(0, pos) + subdir; |
|
44 | pypath = selfpath.substr(0, pos) + subdir; | |
@@ -34,11 +48,24 b' void initpy(const char *cselfpath)' | |||||
34 | setenv("PYTHONNOUSERSITE", "1", 1); |
|
48 | setenv("PYTHONNOUSERSITE", "1", 1); | |
35 | /* prevent Python from looking up users in the fuzz environment */ |
|
49 | /* prevent Python from looking up users in the fuzz environment */ | |
36 | setenv("PYTHONUSERBASE", cpypath, 1); |
|
50 | setenv("PYTHONUSERBASE", cpypath, 1); | |
|
51 | #ifdef HG_FUZZER_PY3 | |||
|
52 | std::wstring wcpypath(pypath.begin(), pypath.end()); | |||
|
53 | Py_SetPythonHome(wcpypath.c_str()); | |||
|
54 | #else | |||
37 | Py_SetPythonHome(cpypath); |
|
55 | Py_SetPythonHome(cpypath); | |
|
56 | #endif | |||
38 | Py_InitializeEx(0); |
|
57 | Py_InitializeEx(0); | |
39 | mainmod = PyImport_AddModule("__main__"); |
|
58 | mainmod = PyImport_AddModule("__main__"); | |
40 | globals = PyModule_GetDict(mainmod); |
|
59 | globals = PyModule_GetDict(mainmod); | |
|
60 | ||||
|
61 | #ifdef HG_FUZZER_PY3 | |||
|
62 | PyObject *mod = PyInit_parsers(); | |||
|
63 | #else | |||
41 | initparsers(); |
|
64 | initparsers(); | |
|
65 | PyObject *mod = PyImport_ImportModule("parsers"); | |||
|
66 | #endif | |||
|
67 | ||||
|
68 | PyDict_SetItemString(globals, "parsers", mod); | |||
42 | } |
|
69 | } | |
43 |
|
70 | |||
44 | PyObject *pyglobals() |
|
71 | PyObject *pyglobals() |
@@ -1,5 +1,11 b'' | |||||
1 | #include <Python.h> |
|
1 | #include <Python.h> | |
2 |
|
2 | |||
|
3 | #if PY_MAJOR_VERSION >= 3 | |||
|
4 | #define PYCODETYPE PyObject | |||
|
5 | #else | |||
|
6 | #define PYCODETYPE PyCodeObject | |||
|
7 | #endif | |||
|
8 | ||||
3 | namespace contrib |
|
9 | namespace contrib | |
4 | { |
|
10 | { | |
5 |
|
11 |
@@ -9,16 +9,15 b'' | |||||
9 |
|
9 | |||
10 | extern "C" { |
|
10 | extern "C" { | |
11 |
|
11 | |||
12 |
static P |
|
12 | static PYCODETYPE *code; | |
13 |
|
13 | |||
14 | extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) |
|
14 | extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) | |
15 | { |
|
15 | { | |
16 | contrib::initpy(*argv[0]); |
|
16 | contrib::initpy(*argv[0]); | |
17 |
code = (P |
|
17 | code = (PYCODETYPE *)Py_CompileString(R"py( | |
18 | from parsers import parse_index2 |
|
|||
19 | for inline in (True, False): |
|
18 | for inline in (True, False): | |
20 | try: |
|
19 | try: | |
21 | index, cache = parse_index2(data, inline) |
|
20 | index, cache = parsers.parse_index2(data, inline) | |
22 | index.slicechunktodensity(list(range(len(index))), 0.5, 262144) |
|
21 | index.slicechunktodensity(list(range(len(index))), 0.5, 262144) | |
23 | index.stats() |
|
22 | index.stats() | |
24 | index.findsnapshots({}, 0) |
|
23 | index.findsnapshots({}, 0) | |
@@ -35,7 +34,7 b' for inline in (True, False):' | |||||
35 | # to debug failures. |
|
34 | # to debug failures. | |
36 | # print e |
|
35 | # print e | |
37 | )py", |
|
36 | )py", | |
38 |
|
|
37 | "fuzzer", Py_file_input); | |
39 | return 0; |
|
38 | return 0; | |
40 | } |
|
39 | } | |
41 |
|
40 |
@@ -1,4 +1,4 b'' | |||||
1 |
from __future__ import absolute_import |
|
1 | from __future__ import absolute_import | |
2 |
|
2 | |||
3 | import argparse |
|
3 | import argparse | |
4 | import os |
|
4 | import os | |
@@ -16,13 +16,10 b' contributing = os.path.join(' | |||||
16 | reporoot, '.hg', 'store', 'data', 'contrib', 'fuzz', 'mpatch.cc.i' |
|
16 | reporoot, '.hg', 'store', 'data', 'contrib', 'fuzz', 'mpatch.cc.i' | |
17 | ) |
|
17 | ) | |
18 |
|
18 | |||
19 | print(changelog, os.path.exists(changelog)) |
|
|||
20 | print(contributing, os.path.exists(contributing)) |
|
|||
21 |
|
||||
22 | with zipfile.ZipFile(args.out[0], "w", zipfile.ZIP_STORED) as zf: |
|
19 | with zipfile.ZipFile(args.out[0], "w", zipfile.ZIP_STORED) as zf: | |
23 | if os.path.exists(changelog): |
|
20 | if os.path.exists(changelog): | |
24 | with open(changelog) as f: |
|
21 | with open(changelog, 'rb') as f: | |
25 | zf.writestr("00changelog.i", f.read()) |
|
22 | zf.writestr("00changelog.i", f.read()) | |
26 | if os.path.exists(contributing): |
|
23 | if os.path.exists(contributing): | |
27 | with open(contributing) as f: |
|
24 | with open(contributing, 'rb') as f: | |
28 | zf.writestr("contributing.i", f.read()) |
|
25 | zf.writestr("contributing.i", f.read()) |
@@ -10,10 +10,15 b'' | |||||
10 | #include <inttypes.h> |
|
10 | #include <inttypes.h> | |
11 | #include <stdlib.h> |
|
11 | #include <stdlib.h> | |
12 |
|
12 | |||
13 |
#include " |
|
13 | #include "FuzzedDataProvider.h" | |
14 |
|
14 | |||
15 | extern "C" { |
|
15 | extern "C" { | |
16 |
|
16 | |||
|
17 | int LLVMFuzzerInitialize(int *argc, char ***argv) | |||
|
18 | { | |||
|
19 | return 0; | |||
|
20 | } | |||
|
21 | ||||
17 | int hunk_consumer(long a1, long a2, long b1, long b2, void *priv) |
|
22 | int hunk_consumer(long a1, long a2, long b1, long b2, void *priv) | |
18 | { |
|
23 | { | |
19 | // TODO: probably also test returning -1 from this when things break? |
|
24 | // TODO: probably also test returning -1 from this when things break? | |
@@ -27,17 +32,15 b' int LLVMFuzzerTestOneInput(const uint8_t' | |||||
27 | if (Size > 100000) { |
|
32 | if (Size > 100000) { | |
28 | return 0; |
|
33 | return 0; | |
29 | } |
|
34 | } | |
30 | auto maybe_inputs = SplitInputs(Data, Size); |
|
35 | FuzzedDataProvider provider(Data, Size); | |
31 | if (!maybe_inputs) { |
|
36 | std::string left = provider.ConsumeRandomLengthString(Size); | |
32 | return 0; |
|
37 | std::string right = provider.ConsumeRemainingBytesAsString(); | |
33 | } |
|
|||
34 | auto inputs = std::move(maybe_inputs.value()); |
|
|||
35 | mmfile_t a, b; |
|
38 | mmfile_t a, b; | |
36 |
|
39 | |||
37 |
a.ptr = |
|
40 | a.ptr = (char *)left.c_str(); | |
38 |
a.size = |
|
41 | a.size = left.size(); | |
39 |
b.ptr = |
|
42 | b.ptr = (char *)right.c_str(); | |
40 |
b.size = |
|
43 | b.size = right.size(); | |
41 | xpparam_t xpp = { |
|
44 | xpparam_t xpp = { | |
42 | XDF_INDENT_HEURISTIC, /* flags */ |
|
45 | XDF_INDENT_HEURISTIC, /* flags */ | |
43 | }; |
|
46 | }; | |
@@ -52,12 +55,4 b' int LLVMFuzzerTestOneInput(const uint8_t' | |||||
52 | return 0; // Non-zero return values are reserved for future use. |
|
55 | return 0; // Non-zero return values are reserved for future use. | |
53 | } |
|
56 | } | |
54 |
|
57 | |||
55 | #ifdef HG_FUZZER_INCLUDE_MAIN |
|
|||
56 | int main(int argc, char **argv) |
|
|||
57 | { |
|
|||
58 | const char data[] = "asdf"; |
|
|||
59 | return LLVMFuzzerTestOneInput((const uint8_t *)data, 4); |
|
|||
60 | } |
|
|||
61 | #endif |
|
|||
62 |
|
||||
63 | } // extern "C" |
|
58 | } // extern "C" |
@@ -35,7 +35,9 b' import shlex' | |||||
35 | import sys |
|
35 | import sys | |
36 |
|
36 | |||
37 | # enable importing on demand to reduce startup time |
|
37 | # enable importing on demand to reduce startup time | |
38 |
import hgdemandimport |
|
38 | import hgdemandimport | |
|
39 | ||||
|
40 | hgdemandimport.enable() | |||
39 |
|
41 | |||
40 | from mercurial import ( |
|
42 | from mercurial import ( | |
41 | dispatch, |
|
43 | dispatch, | |
@@ -43,6 +45,7 b' from mercurial import (' | |||||
43 | ui as uimod, |
|
45 | ui as uimod, | |
44 | ) |
|
46 | ) | |
45 |
|
47 | |||
|
48 | ||||
46 | def main(): |
|
49 | def main(): | |
47 | # Prevent insertion/deletion of CRs |
|
50 | # Prevent insertion/deletion of CRs | |
48 | dispatch.initstdio() |
|
51 | dispatch.initstdio() | |
@@ -56,9 +59,10 b' def main():' | |||||
56 | args.pop(0) |
|
59 | args.pop(0) | |
57 | else: |
|
60 | else: | |
58 | break |
|
61 | break | |
59 | allowed_paths = [os.path.normpath(os.path.join(cwd, |
|
62 | allowed_paths = [ | |
60 | os.path.expanduser(path))) |
|
63 | os.path.normpath(os.path.join(cwd, os.path.expanduser(path))) | |
61 |
|
|
64 | for path in args | |
|
65 | ] | |||
62 | orig_cmd = os.getenv('SSH_ORIGINAL_COMMAND', '?') |
|
66 | orig_cmd = os.getenv('SSH_ORIGINAL_COMMAND', '?') | |
63 | try: |
|
67 | try: | |
64 | cmdargv = shlex.split(orig_cmd) |
|
68 | cmdargv = shlex.split(orig_cmd) | |
@@ -75,10 +79,18 b' def main():' | |||||
75 | if readonly: |
|
79 | if readonly: | |
76 | if not req.ui: |
|
80 | if not req.ui: | |
77 | req.ui = uimod.ui.load() |
|
81 | req.ui = uimod.ui.load() | |
78 |
req.ui.setconfig( |
|
82 | req.ui.setconfig( | |
79 | b'python:__main__.rejectpush', b'hg-ssh') |
|
83 | b'hooks', | |
80 |
|
|
84 | b'pretxnopen.hg-ssh', | |
81 |
|
|
85 | b'python:__main__.rejectpush', | |
|
86 | b'hg-ssh', | |||
|
87 | ) | |||
|
88 | req.ui.setconfig( | |||
|
89 | b'hooks', | |||
|
90 | b'prepushkey.hg-ssh', | |||
|
91 | b'python:__main__.rejectpush', | |||
|
92 | b'hg-ssh', | |||
|
93 | ) | |||
82 | dispatch.dispatch(req) |
|
94 | dispatch.dispatch(req) | |
83 | else: |
|
95 | else: | |
84 | sys.stderr.write('Illegal repository "%s"\n' % repo) |
|
96 | sys.stderr.write('Illegal repository "%s"\n' % repo) | |
@@ -87,11 +99,13 b' def main():' | |||||
87 | sys.stderr.write('Illegal command "%s"\n' % orig_cmd) |
|
99 | sys.stderr.write('Illegal command "%s"\n' % orig_cmd) | |
88 | sys.exit(255) |
|
100 | sys.exit(255) | |
89 |
|
101 | |||
|
102 | ||||
90 | def rejectpush(ui, **kwargs): |
|
103 | def rejectpush(ui, **kwargs): | |
91 | ui.warn((b"Permission denied\n")) |
|
104 | ui.warn((b"Permission denied\n")) | |
92 | # mercurial hooks use unix process conventions for hook return values |
|
105 | # mercurial hooks use unix process conventions for hook return values | |
93 | # so a truthy return means failure |
|
106 | # so a truthy return means failure | |
94 | return True |
|
107 | return True | |
95 |
|
108 | |||
|
109 | ||||
96 | if __name__ == '__main__': |
|
110 | if __name__ == '__main__': | |
97 | main() |
|
111 | main() |
@@ -39,7 +39,7 b' def connectpipe(path=None, extraargs=())' | |||||
39 | cmdline.extend(extraargs) |
|
39 | cmdline.extend(extraargs) | |
40 |
|
40 | |||
41 | def tonative(cmdline): |
|
41 | def tonative(cmdline): | |
42 |
if os.name != |
|
42 | if os.name != 'nt': | |
43 | return cmdline |
|
43 | return cmdline | |
44 | return [arg.decode("utf-8") for arg in cmdline] |
|
44 | return [arg.decode("utf-8") for arg in cmdline] | |
45 |
|
45 |
@@ -37,18 +37,24 b" libdir = '@LIBDIR@'" | |||||
37 |
|
37 | |||
38 | if libdir != '@' 'LIBDIR' '@': |
|
38 | if libdir != '@' 'LIBDIR' '@': | |
39 | if not os.path.isabs(libdir): |
|
39 | if not os.path.isabs(libdir): | |
40 | libdir = os.path.join(os.path.dirname(os.path.realpath(__file__)), |
|
40 | libdir = os.path.join( | |
41 | libdir) |
|
41 | os.path.dirname(os.path.realpath(__file__)), libdir | |
|
42 | ) | |||
42 | libdir = os.path.abspath(libdir) |
|
43 | libdir = os.path.abspath(libdir) | |
43 | sys.path.insert(0, libdir) |
|
44 | sys.path.insert(0, libdir) | |
44 |
|
45 | |||
45 | # enable importing on demand to reduce startup time |
|
46 | # enable importing on demand to reduce startup time | |
46 | try: |
|
47 | try: | |
47 |
from mercurial import demandimport |
|
48 | from mercurial import demandimport | |
|
49 | ||||
|
50 | demandimport.enable() | |||
48 | except ImportError: |
|
51 | except ImportError: | |
49 | import sys |
|
52 | import sys | |
50 | sys.stderr.write("abort: couldn't find mercurial libraries in [%s]\n" % |
|
53 | ||
51 | ' '.join(sys.path)) |
|
54 | sys.stderr.write( | |
|
55 | "abort: couldn't find mercurial libraries in [%s]\n" | |||
|
56 | % ' '.join(sys.path) | |||
|
57 | ) | |||
52 | sys.stderr.write("(check your install and PYTHONPATH)\n") |
|
58 | sys.stderr.write("(check your install and PYTHONPATH)\n") | |
53 | sys.exit(-1) |
|
59 | sys.exit(-1) | |
54 |
|
60 | |||
@@ -57,6 +63,7 b' from mercurial import (' | |||||
57 | util, |
|
63 | util, | |
58 | ) |
|
64 | ) | |
59 |
|
65 | |||
|
66 | ||||
60 | def timer(func, title=None): |
|
67 | def timer(func, title=None): | |
61 | results = [] |
|
68 | results = [] | |
62 | begin = util.timer() |
|
69 | begin = util.timer() | |
@@ -69,7 +76,7 b' def timer(func, title=None):' | |||||
69 | ostop = os.times() |
|
76 | ostop = os.times() | |
70 | count += 1 |
|
77 | count += 1 | |
71 | a, b = ostart, ostop |
|
78 | a, b = ostart, ostop | |
72 | results.append((cstop - cstart, b[0] - a[0], b[1]-a[1])) |
|
79 | results.append((cstop - cstart, b[0] - a[0], b[1] - a[1])) | |
73 | if cstop - begin > 3 and count >= 100: |
|
80 | if cstop - begin > 3 and count >= 100: | |
74 | break |
|
81 | break | |
75 | if cstop - begin > 10 and count >= 3: |
|
82 | if cstop - begin > 10 and count >= 3: | |
@@ -79,19 +86,27 b' def timer(func, title=None):' | |||||
79 | if r: |
|
86 | if r: | |
80 | sys.stderr.write("! result: %s\n" % r) |
|
87 | sys.stderr.write("! result: %s\n" % r) | |
81 | m = min(results) |
|
88 | m = min(results) | |
82 | sys.stderr.write("! wall %f comb %f user %f sys %f (best of %d)\n" |
|
89 | sys.stderr.write( | |
83 | % (m[0], m[1] + m[2], m[1], m[2], count)) |
|
90 | "! wall %f comb %f user %f sys %f (best of %d)\n" | |
|
91 | % (m[0], m[1] + m[2], m[1], m[2], count) | |||
|
92 | ) | |||
|
93 | ||||
84 |
|
94 | |||
85 | orgruncommand = dispatch.runcommand |
|
95 | orgruncommand = dispatch.runcommand | |
86 |
|
96 | |||
|
97 | ||||
87 | def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions): |
|
98 | def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions): | |
88 | ui.pushbuffer() |
|
99 | ui.pushbuffer() | |
89 | lui.pushbuffer() |
|
100 | lui.pushbuffer() | |
90 | timer(lambda : orgruncommand(lui, repo, cmd, fullargs, ui, |
|
101 | timer( | |
91 | options, d, cmdpats, cmdoptions)) |
|
102 | lambda: orgruncommand( | |
|
103 | lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions | |||
|
104 | ) | |||
|
105 | ) | |||
92 | ui.popbuffer() |
|
106 | ui.popbuffer() | |
93 | lui.popbuffer() |
|
107 | lui.popbuffer() | |
94 |
|
108 | |||
|
109 | ||||
95 | dispatch.runcommand = runcommand |
|
110 | dispatch.runcommand = runcommand | |
96 |
|
111 | |||
97 | dispatch.run() |
|
112 | dispatch.run() |
@@ -7,13 +7,16 b' config = "/path/to/repo/or/config"' | |||||
7 |
|
7 | |||
8 | # Uncomment and adjust if Mercurial is not installed system-wide |
|
8 | # Uncomment and adjust if Mercurial is not installed system-wide | |
9 | # (consult "installed modules" path from 'hg debuginstall'): |
|
9 | # (consult "installed modules" path from 'hg debuginstall'): | |
10 | #import sys; sys.path.insert(0, "/path/to/python/lib") |
|
10 | # import sys; sys.path.insert(0, "/path/to/python/lib") | |
11 |
|
11 | |||
12 | # Uncomment to send python tracebacks to the browser if an error occurs: |
|
12 | # Uncomment to send python tracebacks to the browser if an error occurs: | |
13 | #import cgitb; cgitb.enable() |
|
13 | # import cgitb; cgitb.enable() | |
14 |
|
14 | |||
15 |
from mercurial import demandimport |
|
15 | from mercurial import demandimport | |
|
16 | ||||
|
17 | demandimport.enable() | |||
16 | from mercurial.hgweb import hgweb |
|
18 | from mercurial.hgweb import hgweb | |
17 | from flup.server.fcgi import WSGIServer |
|
19 | from flup.server.fcgi import WSGIServer | |
|
20 | ||||
18 | application = hgweb(config) |
|
21 | application = hgweb(config) | |
19 | WSGIServer(application).run() |
|
22 | WSGIServer(application).run() |
@@ -535,6 +535,8 b' def verify_modern_convention(module, roo' | |||||
535 | if fullname != '__future__': |
|
535 | if fullname != '__future__': | |
536 | if not fullname or ( |
|
536 | if not fullname or ( | |
537 | fullname in stdlib_modules |
|
537 | fullname in stdlib_modules | |
|
538 | # allow standard 'from typing import ...' style | |||
|
539 | and fullname.startswith('.') | |||
538 | and fullname not in localmods |
|
540 | and fullname not in localmods | |
539 | and fullname + '.__init__' not in localmods |
|
541 | and fullname + '.__init__' not in localmods | |
540 | ): |
|
542 | ): |
@@ -10,7 +10,8 b' RUN apt-get update && apt-get install -y' | |||||
10 | dh-python \ |
|
10 | dh-python \ | |
11 | less \ |
|
11 | less \ | |
12 | python \ |
|
12 | python \ | |
13 |
python-all |
|
13 | python3-all \ | |
14 |
python |
|
14 | python3-all-dev \ | |
|
15 | python3-docutils \ | |||
15 | unzip \ |
|
16 | unzip \ | |
16 | zip |
|
17 | zip |
@@ -11,6 +11,7 b' import shutil' | |||||
11 | import subprocess |
|
11 | import subprocess | |
12 | import sys |
|
12 | import sys | |
13 |
|
13 | |||
|
14 | ||||
14 | def get_docker() -> str: |
|
15 | def get_docker() -> str: | |
15 | docker = shutil.which('docker.io') or shutil.which('docker') |
|
16 | docker = shutil.which('docker.io') or shutil.which('docker') | |
16 | if not docker: |
|
17 | if not docker: | |
@@ -21,15 +22,16 b' def get_docker() -> str:' | |||||
21 | out = subprocess.check_output([docker, '-h'], stderr=subprocess.STDOUT) |
|
22 | out = subprocess.check_output([docker, '-h'], stderr=subprocess.STDOUT) | |
22 |
|
23 | |||
23 | if b'Jansens' in out: |
|
24 | if b'Jansens' in out: | |
24 | print('%s is the Docking System Tray; try installing docker.io' % |
|
25 | print( | |
25 | docker) |
|
26 | '%s is the Docking System Tray; try installing docker.io' | |
|
27 | % docker | |||
|
28 | ) | |||
26 | sys.exit(1) |
|
29 | sys.exit(1) | |
27 | except subprocess.CalledProcessError as e: |
|
30 | except subprocess.CalledProcessError as e: | |
28 | print('error calling `%s -h`: %s' % (docker, e.output)) |
|
31 | print('error calling `%s -h`: %s' % (docker, e.output)) | |
29 | sys.exit(1) |
|
32 | sys.exit(1) | |
30 |
|
33 | |||
31 | out = subprocess.check_output([docker, 'version'], |
|
34 | out = subprocess.check_output([docker, 'version'], stderr=subprocess.STDOUT) | |
32 | stderr=subprocess.STDOUT) |
|
|||
33 |
|
35 | |||
34 | lines = out.splitlines() |
|
36 | lines = out.splitlines() | |
35 | if not any(l.startswith((b'Client:', b'Client version:')) for l in lines): |
|
37 | if not any(l.startswith((b'Client:', b'Client version:')) for l in lines): | |
@@ -42,6 +44,7 b' def get_docker() -> str:' | |||||
42 |
|
44 | |||
43 | return docker |
|
45 | return docker | |
44 |
|
46 | |||
|
47 | ||||
45 | def get_dockerfile(path: pathlib.Path, args: list) -> bytes: |
|
48 | def get_dockerfile(path: pathlib.Path, args: list) -> bytes: | |
46 | with path.open('rb') as fh: |
|
49 | with path.open('rb') as fh: | |
47 | df = fh.read() |
|
50 | df = fh.read() | |
@@ -51,6 +54,7 b' def get_dockerfile(path: pathlib.Path, a' | |||||
51 |
|
54 | |||
52 | return df |
|
55 | return df | |
53 |
|
56 | |||
|
57 | ||||
54 | def build_docker_image(dockerfile: pathlib.Path, params: list, tag: str): |
|
58 | def build_docker_image(dockerfile: pathlib.Path, params: list, tag: str): | |
55 | """Build a Docker image from a templatized Dockerfile.""" |
|
59 | """Build a Docker image from a templatized Dockerfile.""" | |
56 | docker = get_docker() |
|
60 | docker = get_docker() | |
@@ -65,9 +69,12 b' def build_docker_image(dockerfile: pathl' | |||||
65 | args = [ |
|
69 | args = [ | |
66 | docker, |
|
70 | docker, | |
67 | 'build', |
|
71 | 'build', | |
68 |
'--build-arg', |
|
72 | '--build-arg', | |
69 |
' |
|
73 | 'http_proxy', | |
70 |
'-- |
|
74 | '--build-arg', | |
|
75 | 'https_proxy', | |||
|
76 | '--tag', | |||
|
77 | tag, | |||
71 | '-', |
|
78 | '-', | |
72 | ] |
|
79 | ] | |
73 |
|
80 | |||
@@ -76,8 +83,10 b' def build_docker_image(dockerfile: pathl' | |||||
76 | p.communicate(input=dockerfile) |
|
83 | p.communicate(input=dockerfile) | |
77 | if p.returncode: |
|
84 | if p.returncode: | |
78 | raise subprocess.CalledProcessException( |
|
85 | raise subprocess.CalledProcessException( | |
79 | p.returncode, 'failed to build docker image: %s %s' |
|
86 | p.returncode, | |
80 |
% (p.stdout, p.stderr) |
|
87 | 'failed to build docker image: %s %s' % (p.stdout, p.stderr), | |
|
88 | ) | |||
|
89 | ||||
81 |
|
90 | |||
82 | def command_build(args): |
|
91 | def command_build(args): | |
83 | build_args = [] |
|
92 | build_args = [] | |
@@ -85,13 +94,13 b' def command_build(args):' | |||||
85 | k, v = arg.split('=', 1) |
|
94 | k, v = arg.split('=', 1) | |
86 | build_args.append((k.encode('utf-8'), v.encode('utf-8'))) |
|
95 | build_args.append((k.encode('utf-8'), v.encode('utf-8'))) | |
87 |
|
96 | |||
88 | build_docker_image(pathlib.Path(args.dockerfile), |
|
97 | build_docker_image(pathlib.Path(args.dockerfile), build_args, args.tag) | |
89 | build_args, |
|
98 | ||
90 | args.tag) |
|
|||
91 |
|
99 | |||
92 | def command_docker(args): |
|
100 | def command_docker(args): | |
93 | print(get_docker()) |
|
101 | print(get_docker()) | |
94 |
|
102 | |||
|
103 | ||||
95 | def main() -> int: |
|
104 | def main() -> int: | |
96 | parser = argparse.ArgumentParser() |
|
105 | parser = argparse.ArgumentParser() | |
97 |
|
106 | |||
@@ -99,9 +108,12 b' def main() -> int:' | |||||
99 |
|
108 | |||
100 | build = subparsers.add_parser('build', help='Build a Docker image') |
|
109 | build = subparsers.add_parser('build', help='Build a Docker image') | |
101 | build.set_defaults(func=command_build) |
|
110 | build.set_defaults(func=command_build) | |
102 | build.add_argument('--build-arg', action='append', default=[], |
|
111 | build.add_argument( | |
103 | help='Substitution to perform in Dockerfile; ' |
|
112 | '--build-arg', | |
104 | 'format: key=value') |
|
113 | action='append', | |
|
114 | default=[], | |||
|
115 | help='Substitution to perform in Dockerfile; ' 'format: key=value', | |||
|
116 | ) | |||
105 | build.add_argument('dockerfile', help='path to Dockerfile to use') |
|
117 | build.add_argument('dockerfile', help='path to Dockerfile to use') | |
106 | build.add_argument('tag', help='Tag to apply to created image') |
|
118 | build.add_argument('tag', help='Tag to apply to created image') | |
107 |
|
119 | |||
@@ -112,5 +124,6 b' def main() -> int:' | |||||
112 |
|
124 | |||
113 | return args.func(args) |
|
125 | return args.func(args) | |
114 |
|
126 | |||
|
127 | ||||
115 | if __name__ == '__main__': |
|
128 | if __name__ == '__main__': | |
116 | sys.exit(main()) |
|
129 | sys.exit(main()) |
@@ -12,9 +12,16 b' import pathlib' | |||||
12 | import shutil |
|
12 | import shutil | |
13 | import subprocess |
|
13 | import subprocess | |
14 |
|
14 | |||
15 | from .py2exe import build_py2exe |
|
15 | import jinja2 | |
16 | from .util import find_vc_runtime_files |
|
|||
17 |
|
16 | |||
|
17 | from .py2exe import ( | |||
|
18 | build_py2exe, | |||
|
19 | stage_install, | |||
|
20 | ) | |||
|
21 | from .util import ( | |||
|
22 | find_vc_runtime_files, | |||
|
23 | read_version_py, | |||
|
24 | ) | |||
18 |
|
25 | |||
19 | EXTRA_PACKAGES = { |
|
26 | EXTRA_PACKAGES = { | |
20 | 'dulwich', |
|
27 | 'dulwich', | |
@@ -23,6 +30,10 b' EXTRA_PACKAGES = {' | |||||
23 | 'win32ctypes', |
|
30 | 'win32ctypes', | |
24 | } |
|
31 | } | |
25 |
|
32 | |||
|
33 | PACKAGE_FILES_METADATA = { | |||
|
34 | 'ReadMe.html': 'Flags: isreadme', | |||
|
35 | } | |||
|
36 | ||||
26 |
|
37 | |||
27 | def build( |
|
38 | def build( | |
28 | source_dir: pathlib.Path, |
|
39 | source_dir: pathlib.Path, | |
@@ -43,11 +54,17 b' def build(' | |||||
43 | raise Exception('%s does not exist' % iscc_exe) |
|
54 | raise Exception('%s does not exist' % iscc_exe) | |
44 |
|
55 | |||
45 | vc_x64 = r'\x64' in os.environ.get('LIB', '') |
|
56 | vc_x64 = r'\x64' in os.environ.get('LIB', '') | |
|
57 | arch = 'x64' if vc_x64 else 'x86' | |||
|
58 | inno_source_dir = source_dir / 'contrib' / 'packaging' / 'inno' | |||
|
59 | inno_build_dir = build_dir / ('inno-%s' % arch) | |||
|
60 | staging_dir = inno_build_dir / 'stage' | |||
46 |
|
61 | |||
47 | requirements_txt = ( |
|
62 | requirements_txt = ( | |
48 | source_dir / 'contrib' / 'packaging' / 'inno' / 'requirements.txt' |
|
63 | source_dir / 'contrib' / 'packaging' / 'inno' / 'requirements.txt' | |
49 | ) |
|
64 | ) | |
50 |
|
65 | |||
|
66 | inno_build_dir.mkdir(parents=True, exist_ok=True) | |||
|
67 | ||||
51 | build_py2exe( |
|
68 | build_py2exe( | |
52 | source_dir, |
|
69 | source_dir, | |
53 | build_dir, |
|
70 | build_dir, | |
@@ -57,6 +74,15 b' def build(' | |||||
57 | extra_packages=EXTRA_PACKAGES, |
|
74 | extra_packages=EXTRA_PACKAGES, | |
58 | ) |
|
75 | ) | |
59 |
|
76 | |||
|
77 | # Purge the staging directory for every build so packaging is | |||
|
78 | # pristine. | |||
|
79 | if staging_dir.exists(): | |||
|
80 | print('purging %s' % staging_dir) | |||
|
81 | shutil.rmtree(staging_dir) | |||
|
82 | ||||
|
83 | # Now assemble all the packaged files into the staging directory. | |||
|
84 | stage_install(source_dir, staging_dir) | |||
|
85 | ||||
60 | # hg.exe depends on VC9 runtime DLLs. Copy those into place. |
|
86 | # hg.exe depends on VC9 runtime DLLs. Copy those into place. | |
61 | for f in find_vc_runtime_files(vc_x64): |
|
87 | for f in find_vc_runtime_files(vc_x64): | |
62 | if f.name.endswith('.manifest'): |
|
88 | if f.name.endswith('.manifest'): | |
@@ -64,22 +90,74 b' def build(' | |||||
64 | else: |
|
90 | else: | |
65 | basename = f.name |
|
91 | basename = f.name | |
66 |
|
92 | |||
67 |
dest_path = s |
|
93 | dest_path = staging_dir / basename | |
68 |
|
94 | |||
69 | print('copying %s to %s' % (f, dest_path)) |
|
95 | print('copying %s to %s' % (f, dest_path)) | |
70 | shutil.copyfile(f, dest_path) |
|
96 | shutil.copyfile(f, dest_path) | |
71 |
|
97 | |||
|
98 | # The final package layout is simply a mirror of the staging directory. | |||
|
99 | package_files = [] | |||
|
100 | for root, dirs, files in os.walk(staging_dir): | |||
|
101 | dirs.sort() | |||
|
102 | ||||
|
103 | root = pathlib.Path(root) | |||
|
104 | ||||
|
105 | for f in sorted(files): | |||
|
106 | full = root / f | |||
|
107 | rel = full.relative_to(staging_dir) | |||
|
108 | if str(rel.parent) == '.': | |||
|
109 | dest_dir = '{app}' | |||
|
110 | else: | |||
|
111 | dest_dir = '{app}\\%s' % rel.parent | |||
|
112 | ||||
|
113 | package_files.append( | |||
|
114 | { | |||
|
115 | 'source': rel, | |||
|
116 | 'dest_dir': dest_dir, | |||
|
117 | 'metadata': PACKAGE_FILES_METADATA.get(str(rel), None), | |||
|
118 | } | |||
|
119 | ) | |||
|
120 | ||||
72 | print('creating installer') |
|
121 | print('creating installer') | |
73 |
|
122 | |||
|
123 | # Install Inno files by rendering a template. | |||
|
124 | jinja_env = jinja2.Environment( | |||
|
125 | loader=jinja2.FileSystemLoader(str(inno_source_dir)), | |||
|
126 | # Need to change these to prevent conflict with Inno Setup. | |||
|
127 | comment_start_string='{##', | |||
|
128 | comment_end_string='##}', | |||
|
129 | ) | |||
|
130 | ||||
|
131 | try: | |||
|
132 | template = jinja_env.get_template('mercurial.iss') | |||
|
133 | except jinja2.TemplateSyntaxError as e: | |||
|
134 | raise Exception( | |||
|
135 | 'template syntax error at %s:%d: %s' | |||
|
136 | % (e.name, e.lineno, e.message,) | |||
|
137 | ) | |||
|
138 | ||||
|
139 | content = template.render(package_files=package_files) | |||
|
140 | ||||
|
141 | with (inno_build_dir / 'mercurial.iss').open('w', encoding='utf-8') as fh: | |||
|
142 | fh.write(content) | |||
|
143 | ||||
|
144 | # Copy additional files used by Inno. | |||
|
145 | for p in ('mercurial.ico', 'postinstall.txt'): | |||
|
146 | shutil.copyfile( | |||
|
147 | source_dir / 'contrib' / 'win32' / p, inno_build_dir / p | |||
|
148 | ) | |||
|
149 | ||||
74 | args = [str(iscc_exe)] |
|
150 | args = [str(iscc_exe)] | |
75 |
|
151 | |||
76 | if vc_x64: |
|
152 | if vc_x64: | |
77 | args.append('/dARCH=x64') |
|
153 | args.append('/dARCH=x64') | |
78 |
|
154 | |||
79 | if version: |
|
155 | if not version: | |
80 | args.append('/dVERSION=%s' % version) |
|
156 | version = read_version_py(source_dir) | |
|
157 | ||||
|
158 | args.append('/dVERSION=%s' % version) | |||
81 |
|
159 | |||
82 | args.append('/Odist') |
|
160 | args.append('/Odist') | |
83 |
args.append(' |
|
161 | args.append(str(inno_build_dir / 'mercurial.iss')) | |
84 |
|
162 | |||
85 | subprocess.run(args, cwd=str(source_dir), check=True) |
|
163 | subprocess.run(args, cwd=str(source_dir), check=True) |
@@ -15,10 +15,48 b' from .downloads import download_entry' | |||||
15 | from .util import ( |
|
15 | from .util import ( | |
16 | extract_tar_to_directory, |
|
16 | extract_tar_to_directory, | |
17 | extract_zip_to_directory, |
|
17 | extract_zip_to_directory, | |
|
18 | process_install_rules, | |||
18 | python_exe_info, |
|
19 | python_exe_info, | |
19 | ) |
|
20 | ) | |
20 |
|
21 | |||
21 |
|
22 | |||
|
23 | STAGING_RULES = [ | |||
|
24 | ('contrib/bash_completion', 'Contrib/'), | |||
|
25 | ('contrib/hgk', 'Contrib/hgk.tcl'), | |||
|
26 | ('contrib/hgweb.fcgi', 'Contrib/'), | |||
|
27 | ('contrib/hgweb.wsgi', 'Contrib/'), | |||
|
28 | ('contrib/logo-droplets.svg', 'Contrib/'), | |||
|
29 | ('contrib/mercurial.el', 'Contrib/'), | |||
|
30 | ('contrib/mq.el', 'Contrib/'), | |||
|
31 | ('contrib/tcsh_completion', 'Contrib/'), | |||
|
32 | ('contrib/tcsh_completion_build.sh', 'Contrib/'), | |||
|
33 | ('contrib/vim/*', 'Contrib/Vim/'), | |||
|
34 | ('contrib/win32/postinstall.txt', 'ReleaseNotes.txt'), | |||
|
35 | ('contrib/win32/ReadMe.html', 'ReadMe.html'), | |||
|
36 | ('contrib/xml.rnc', 'Contrib/'), | |||
|
37 | ('contrib/zsh_completion', 'Contrib/'), | |||
|
38 | ('dist/hg.exe', './'), | |||
|
39 | ('dist/lib/*.dll', 'lib/'), | |||
|
40 | ('dist/lib/*.pyd', 'lib/'), | |||
|
41 | ('dist/lib/library.zip', 'lib/'), | |||
|
42 | ('dist/Microsoft.VC*.CRT.manifest', './'), | |||
|
43 | ('dist/msvc*.dll', './'), | |||
|
44 | ('dist/python*.dll', './'), | |||
|
45 | ('doc/*.html', 'doc/'), | |||
|
46 | ('doc/style.css', 'doc/'), | |||
|
47 | ('mercurial/helptext/**/*.txt', 'helptext/'), | |||
|
48 | ('mercurial/defaultrc/*.rc', 'hgrc.d/'), | |||
|
49 | ('mercurial/locale/**/*', 'locale/'), | |||
|
50 | ('mercurial/templates/**/*', 'Templates/'), | |||
|
51 | ('COPYING', 'Copying.txt'), | |||
|
52 | ] | |||
|
53 | ||||
|
54 | # List of paths to exclude from the staging area. | |||
|
55 | STAGING_EXCLUDES = [ | |||
|
56 | 'doc/hg-ssh.8.html', | |||
|
57 | ] | |||
|
58 | ||||
|
59 | ||||
22 | def build_py2exe( |
|
60 | def build_py2exe( | |
23 | source_dir: pathlib.Path, |
|
61 | source_dir: pathlib.Path, | |
24 | build_dir: pathlib.Path, |
|
62 | build_dir: pathlib.Path, | |
@@ -169,3 +207,39 b' def build_py2exe(' | |||||
169 | env=env, |
|
207 | env=env, | |
170 | check=True, |
|
208 | check=True, | |
171 | ) |
|
209 | ) | |
|
210 | ||||
|
211 | ||||
|
212 | def stage_install( | |||
|
213 | source_dir: pathlib.Path, staging_dir: pathlib.Path, lower_case=False | |||
|
214 | ): | |||
|
215 | """Copy all files to be installed to a directory. | |||
|
216 | ||||
|
217 | This allows packaging to simply walk a directory tree to find source | |||
|
218 | files. | |||
|
219 | """ | |||
|
220 | if lower_case: | |||
|
221 | rules = [] | |||
|
222 | for source, dest in STAGING_RULES: | |||
|
223 | # Only lower directory names. | |||
|
224 | if '/' in dest: | |||
|
225 | parent, leaf = dest.rsplit('/', 1) | |||
|
226 | dest = '%s/%s' % (parent.lower(), leaf) | |||
|
227 | rules.append((source, dest)) | |||
|
228 | else: | |||
|
229 | rules = STAGING_RULES | |||
|
230 | ||||
|
231 | process_install_rules(rules, source_dir, staging_dir) | |||
|
232 | ||||
|
233 | # Write out a default editor.rc file to configure notepad as the | |||
|
234 | # default editor. | |||
|
235 | with (staging_dir / 'hgrc.d' / 'editor.rc').open( | |||
|
236 | 'w', encoding='utf-8' | |||
|
237 | ) as fh: | |||
|
238 | fh.write('[ui]\neditor = notepad\n') | |||
|
239 | ||||
|
240 | # Purge any files we don't want to be there. | |||
|
241 | for f in STAGING_EXCLUDES: | |||
|
242 | p = staging_dir / f | |||
|
243 | if p.exists(): | |||
|
244 | print('removing %s' % p) | |||
|
245 | p.unlink() |
@@ -9,8 +9,11 b'' | |||||
9 |
|
9 | |||
10 | import distutils.version |
|
10 | import distutils.version | |
11 | import getpass |
|
11 | import getpass | |
|
12 | import glob | |||
12 | import os |
|
13 | import os | |
13 | import pathlib |
|
14 | import pathlib | |
|
15 | import re | |||
|
16 | import shutil | |||
14 | import subprocess |
|
17 | import subprocess | |
15 | import tarfile |
|
18 | import tarfile | |
16 | import zipfile |
|
19 | import zipfile | |
@@ -164,3 +167,60 b' def python_exe_info(python_exe: pathlib.' | |||||
164 | 'version': version, |
|
167 | 'version': version, | |
165 | 'py3': version >= distutils.version.LooseVersion('3'), |
|
168 | 'py3': version >= distutils.version.LooseVersion('3'), | |
166 | } |
|
169 | } | |
|
170 | ||||
|
171 | ||||
|
172 | def process_install_rules( | |||
|
173 | rules: list, source_dir: pathlib.Path, dest_dir: pathlib.Path | |||
|
174 | ): | |||
|
175 | for source, dest in rules: | |||
|
176 | if '*' in source: | |||
|
177 | if not dest.endswith('/'): | |||
|
178 | raise ValueError('destination must end in / when globbing') | |||
|
179 | ||||
|
180 | # We strip off the source path component before the first glob | |||
|
181 | # character to construct the relative install path. | |||
|
182 | prefix_end_index = source[: source.index('*')].rindex('/') | |||
|
183 | relative_prefix = source_dir / source[0:prefix_end_index] | |||
|
184 | ||||
|
185 | for res in glob.glob(str(source_dir / source), recursive=True): | |||
|
186 | source_path = pathlib.Path(res) | |||
|
187 | ||||
|
188 | if source_path.is_dir(): | |||
|
189 | continue | |||
|
190 | ||||
|
191 | rel_path = source_path.relative_to(relative_prefix) | |||
|
192 | ||||
|
193 | dest_path = dest_dir / dest[:-1] / rel_path | |||
|
194 | ||||
|
195 | dest_path.parent.mkdir(parents=True, exist_ok=True) | |||
|
196 | print('copying %s to %s' % (source_path, dest_path)) | |||
|
197 | shutil.copy(source_path, dest_path) | |||
|
198 | ||||
|
199 | # Simple file case. | |||
|
200 | else: | |||
|
201 | source_path = pathlib.Path(source) | |||
|
202 | ||||
|
203 | if dest.endswith('/'): | |||
|
204 | dest_path = pathlib.Path(dest) / source_path.name | |||
|
205 | else: | |||
|
206 | dest_path = pathlib.Path(dest) | |||
|
207 | ||||
|
208 | full_source_path = source_dir / source_path | |||
|
209 | full_dest_path = dest_dir / dest_path | |||
|
210 | ||||
|
211 | full_dest_path.parent.mkdir(parents=True, exist_ok=True) | |||
|
212 | shutil.copy(full_source_path, full_dest_path) | |||
|
213 | print('copying %s to %s' % (full_source_path, full_dest_path)) | |||
|
214 | ||||
|
215 | ||||
|
216 | def read_version_py(source_dir): | |||
|
217 | """Read the mercurial/__version__.py file to resolve the version string.""" | |||
|
218 | p = source_dir / 'mercurial' / '__version__.py' | |||
|
219 | ||||
|
220 | with p.open('r', encoding='utf-8') as fh: | |||
|
221 | m = re.search('version = b"([^"]+)"', fh.read(), re.MULTILINE) | |||
|
222 | ||||
|
223 | if not m: | |||
|
224 | raise Exception('could not parse %s' % p) | |||
|
225 | ||||
|
226 | return m.group(1) |
@@ -7,39 +7,60 b'' | |||||
7 |
|
7 | |||
8 | # no-check-code because Python 3 native. |
|
8 | # no-check-code because Python 3 native. | |
9 |
|
9 | |||
|
10 | import collections | |||
10 | import os |
|
11 | import os | |
11 | import pathlib |
|
12 | import pathlib | |
12 | import re |
|
13 | import re | |
|
14 | import shutil | |||
13 | import subprocess |
|
15 | import subprocess | |
14 | import tempfile |
|
|||
15 | import typing |
|
16 | import typing | |
|
17 | import uuid | |||
16 | import xml.dom.minidom |
|
18 | import xml.dom.minidom | |
17 |
|
19 | |||
18 | from .downloads import download_entry |
|
20 | from .downloads import download_entry | |
19 |
from .py2exe import |
|
21 | from .py2exe import ( | |
|
22 | build_py2exe, | |||
|
23 | stage_install, | |||
|
24 | ) | |||
20 | from .util import ( |
|
25 | from .util import ( | |
21 | extract_zip_to_directory, |
|
26 | extract_zip_to_directory, | |
|
27 | process_install_rules, | |||
22 | sign_with_signtool, |
|
28 | sign_with_signtool, | |
23 | ) |
|
29 | ) | |
24 |
|
30 | |||
25 |
|
31 | |||
26 | SUPPORT_WXS = [ |
|
|||
27 | ('contrib.wxs', r'contrib'), |
|
|||
28 | ('dist.wxs', r'dist'), |
|
|||
29 | ('doc.wxs', r'doc'), |
|
|||
30 | ('help.wxs', r'mercurial\help'), |
|
|||
31 | ('i18n.wxs', r'i18n'), |
|
|||
32 | ('locale.wxs', r'mercurial\locale'), |
|
|||
33 | ('templates.wxs', r'mercurial\templates'), |
|
|||
34 | ] |
|
|||
35 |
|
||||
36 |
|
||||
37 | EXTRA_PACKAGES = { |
|
32 | EXTRA_PACKAGES = { | |
38 | 'distutils', |
|
33 | 'distutils', | |
39 | 'pygments', |
|
34 | 'pygments', | |
40 | } |
|
35 | } | |
41 |
|
36 | |||
42 |
|
37 | |||
|
38 | EXTRA_INSTALL_RULES = [ | |||
|
39 | ('contrib/packaging/wix/COPYING.rtf', 'COPYING.rtf'), | |||
|
40 | ('contrib/win32/mercurial.ini', 'hgrc.d/mercurial.rc'), | |||
|
41 | ] | |||
|
42 | ||||
|
43 | STAGING_REMOVE_FILES = [ | |||
|
44 | # We use the RTF variant. | |||
|
45 | 'copying.txt', | |||
|
46 | ] | |||
|
47 | ||||
|
48 | SHORTCUTS = { | |||
|
49 | # hg.1.html' | |||
|
50 | 'hg.file.5d3e441c_28d9_5542_afd0_cdd4234f12d5': { | |||
|
51 | 'Name': 'Mercurial Command Reference', | |||
|
52 | }, | |||
|
53 | # hgignore.5.html | |||
|
54 | 'hg.file.5757d8e0_f207_5e10_a2ec_3ba0a062f431': { | |||
|
55 | 'Name': 'Mercurial Ignore Files', | |||
|
56 | }, | |||
|
57 | # hgrc.5.html | |||
|
58 | 'hg.file.92e605fd_1d1a_5dc6_9fc0_5d2998eb8f5e': { | |||
|
59 | 'Name': 'Mercurial Configuration Files', | |||
|
60 | }, | |||
|
61 | } | |||
|
62 | ||||
|
63 | ||||
43 | def find_version(source_dir: pathlib.Path): |
|
64 | def find_version(source_dir: pathlib.Path): | |
44 | version_py = source_dir / 'mercurial' / '__version__.py' |
|
65 | version_py = source_dir / 'mercurial' / '__version__.py' | |
45 |
|
66 | |||
@@ -148,49 +169,165 b' def make_post_build_signing_fn(' | |||||
148 | return post_build_sign |
|
169 | return post_build_sign | |
149 |
|
170 | |||
150 |
|
171 | |||
151 | LIBRARIES_XML = ''' |
|
172 | def make_files_xml(staging_dir: pathlib.Path, is_x64) -> str: | |
152 | <?xml version="1.0" encoding="utf-8"?> |
|
173 | """Create XML string listing every file to be installed.""" | |
153 | <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> |
|
|||
154 |
|
||||
155 | <?include {wix_dir}/guids.wxi ?> |
|
|||
156 | <?include {wix_dir}/defines.wxi ?> |
|
|||
157 |
|
174 | |||
158 | <Fragment> |
|
175 | # We derive GUIDs from a deterministic file path identifier. | |
159 | <DirectoryRef Id="INSTALLDIR" FileSource="$(var.SourceDir)"> |
|
176 | # We shoehorn the name into something that looks like a URL because | |
160 | <Directory Id="libdir" Name="lib" FileSource="$(var.SourceDir)/lib"> |
|
177 | # the UUID namespaces are supposed to work that way (even though | |
161 | <Component Id="libOutput" Guid="$(var.lib.guid)" Win64='$(var.IsX64)'> |
|
178 | # the input data probably is never validated). | |
162 | </Component> |
|
|||
163 | </Directory> |
|
|||
164 | </DirectoryRef> |
|
|||
165 | </Fragment> |
|
|||
166 | </Wix> |
|
|||
167 | '''.lstrip() |
|
|||
168 |
|
179 | |||
169 |
|
||||
170 | def make_libraries_xml(wix_dir: pathlib.Path, dist_dir: pathlib.Path): |
|
|||
171 | """Make XML data for library components WXS.""" |
|
|||
172 | # We can't use ElementTree because it doesn't handle the |
|
|||
173 | # <?include ?> directives. |
|
|||
174 | doc = xml.dom.minidom.parseString( |
|
180 | doc = xml.dom.minidom.parseString( | |
175 | LIBRARIES_XML.format(wix_dir=str(wix_dir)) |
|
181 | '<?xml version="1.0" encoding="utf-8"?>' | |
|
182 | '<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">' | |||
|
183 | '</Wix>' | |||
176 | ) |
|
184 | ) | |
177 |
|
185 | |||
178 | component = doc.getElementsByTagName('Component')[0] |
|
186 | # Assemble the install layout by directory. This makes it easier to | |
|
187 | # emit XML, since each directory has separate entities. | |||
|
188 | manifest = collections.defaultdict(dict) | |||
|
189 | ||||
|
190 | for root, dirs, files in os.walk(staging_dir): | |||
|
191 | dirs.sort() | |||
|
192 | ||||
|
193 | root = pathlib.Path(root) | |||
|
194 | rel_dir = root.relative_to(staging_dir) | |||
|
195 | ||||
|
196 | for i in range(len(rel_dir.parts)): | |||
|
197 | parent = '/'.join(rel_dir.parts[0 : i + 1]) | |||
|
198 | manifest.setdefault(parent, {}) | |||
|
199 | ||||
|
200 | for f in sorted(files): | |||
|
201 | full = root / f | |||
|
202 | manifest[str(rel_dir).replace('\\', '/')][full.name] = full | |||
|
203 | ||||
|
204 | component_groups = collections.defaultdict(list) | |||
|
205 | ||||
|
206 | # Now emit a <Fragment> for each directory. | |||
|
207 | # Each directory is composed of a <DirectoryRef> pointing to its parent | |||
|
208 | # and defines child <Directory>'s and a <Component> with all the files. | |||
|
209 | for dir_name, entries in sorted(manifest.items()): | |||
|
210 | # The directory id is derived from the path. But the root directory | |||
|
211 | # is special. | |||
|
212 | if dir_name == '.': | |||
|
213 | parent_directory_id = 'INSTALLDIR' | |||
|
214 | else: | |||
|
215 | parent_directory_id = 'hg.dir.%s' % dir_name.replace('/', '.') | |||
179 |
|
216 | |||
180 |
f = doc.createElement('F |
|
217 | fragment = doc.createElement('Fragment') | |
181 | f.setAttribute('Name', 'library.zip') |
|
218 | directory_ref = doc.createElement('DirectoryRef') | |
182 | f.setAttribute('KeyPath', 'yes') |
|
219 | directory_ref.setAttribute('Id', parent_directory_id) | |
183 | component.appendChild(f) |
|
220 | ||
|
221 | # Add <Directory> entries for immediate children directories. | |||
|
222 | for possible_child in sorted(manifest.keys()): | |||
|
223 | if ( | |||
|
224 | dir_name == '.' | |||
|
225 | and '/' not in possible_child | |||
|
226 | and possible_child != '.' | |||
|
227 | ): | |||
|
228 | child_directory_id = 'hg.dir.%s' % possible_child | |||
|
229 | name = possible_child | |||
|
230 | else: | |||
|
231 | if not possible_child.startswith('%s/' % dir_name): | |||
|
232 | continue | |||
|
233 | name = possible_child[len(dir_name) + 1 :] | |||
|
234 | if '/' in name: | |||
|
235 | continue | |||
|
236 | ||||
|
237 | child_directory_id = 'hg.dir.%s' % possible_child.replace( | |||
|
238 | '/', '.' | |||
|
239 | ) | |||
|
240 | ||||
|
241 | directory = doc.createElement('Directory') | |||
|
242 | directory.setAttribute('Id', child_directory_id) | |||
|
243 | directory.setAttribute('Name', name) | |||
|
244 | directory_ref.appendChild(directory) | |||
|
245 | ||||
|
246 | # Add <Component>s for files in this directory. | |||
|
247 | for rel, source_path in sorted(entries.items()): | |||
|
248 | if dir_name == '.': | |||
|
249 | full_rel = rel | |||
|
250 | else: | |||
|
251 | full_rel = '%s/%s' % (dir_name, rel) | |||
184 |
|
252 | |||
185 | lib_dir = dist_dir / 'lib' |
|
253 | component_unique_id = ( | |
|
254 | 'https://www.mercurial-scm.org/wix-installer/0/component/%s' | |||
|
255 | % full_rel | |||
|
256 | ) | |||
|
257 | component_guid = uuid.uuid5(uuid.NAMESPACE_URL, component_unique_id) | |||
|
258 | component_id = 'hg.component.%s' % str(component_guid).replace( | |||
|
259 | '-', '_' | |||
|
260 | ) | |||
|
261 | ||||
|
262 | component = doc.createElement('Component') | |||
|
263 | ||||
|
264 | component.setAttribute('Id', component_id) | |||
|
265 | component.setAttribute('Guid', str(component_guid).upper()) | |||
|
266 | component.setAttribute('Win64', 'yes' if is_x64 else 'no') | |||
|
267 | ||||
|
268 | # Assign this component to a top-level group. | |||
|
269 | if dir_name == '.': | |||
|
270 | component_groups['ROOT'].append(component_id) | |||
|
271 | elif '/' in dir_name: | |||
|
272 | component_groups[dir_name[0 : dir_name.index('/')]].append( | |||
|
273 | component_id | |||
|
274 | ) | |||
|
275 | else: | |||
|
276 | component_groups[dir_name].append(component_id) | |||
|
277 | ||||
|
278 | unique_id = ( | |||
|
279 | 'https://www.mercurial-scm.org/wix-installer/0/%s' % full_rel | |||
|
280 | ) | |||
|
281 | file_guid = uuid.uuid5(uuid.NAMESPACE_URL, unique_id) | |||
|
282 | ||||
|
283 | # IDs have length limits. So use GUID to derive them. | |||
|
284 | file_guid_normalized = str(file_guid).replace('-', '_') | |||
|
285 | file_id = 'hg.file.%s' % file_guid_normalized | |||
186 |
|
286 | |||
187 | for p in sorted(lib_dir.iterdir()): |
|
287 | file_element = doc.createElement('File') | |
188 | if not p.name.endswith(('.dll', '.pyd')): |
|
288 | file_element.setAttribute('Id', file_id) | |
189 | continue |
|
289 | file_element.setAttribute('Source', str(source_path)) | |
|
290 | file_element.setAttribute('KeyPath', 'yes') | |||
|
291 | file_element.setAttribute('ReadOnly', 'yes') | |||
|
292 | ||||
|
293 | component.appendChild(file_element) | |||
|
294 | directory_ref.appendChild(component) | |||
|
295 | ||||
|
296 | fragment.appendChild(directory_ref) | |||
|
297 | doc.documentElement.appendChild(fragment) | |||
|
298 | ||||
|
299 | for group, component_ids in sorted(component_groups.items()): | |||
|
300 | fragment = doc.createElement('Fragment') | |||
|
301 | component_group = doc.createElement('ComponentGroup') | |||
|
302 | component_group.setAttribute('Id', 'hg.group.%s' % group) | |||
|
303 | ||||
|
304 | for component_id in component_ids: | |||
|
305 | component_ref = doc.createElement('ComponentRef') | |||
|
306 | component_ref.setAttribute('Id', component_id) | |||
|
307 | component_group.appendChild(component_ref) | |||
190 |
|
308 | |||
191 | f = doc.createElement('File') |
|
309 | fragment.appendChild(component_group) | |
192 | f.setAttribute('Name', p.name) |
|
310 | doc.documentElement.appendChild(fragment) | |
193 | component.appendChild(f) |
|
311 | ||
|
312 | # Add <Shortcut> to files that have it defined. | |||
|
313 | for file_id, metadata in sorted(SHORTCUTS.items()): | |||
|
314 | els = doc.getElementsByTagName('File') | |||
|
315 | els = [el for el in els if el.getAttribute('Id') == file_id] | |||
|
316 | ||||
|
317 | if not els: | |||
|
318 | raise Exception('could not find File[Id=%s]' % file_id) | |||
|
319 | ||||
|
320 | for el in els: | |||
|
321 | shortcut = doc.createElement('Shortcut') | |||
|
322 | shortcut.setAttribute('Id', 'hg.shortcut.%s' % file_id) | |||
|
323 | shortcut.setAttribute('Directory', 'ProgramMenuDir') | |||
|
324 | shortcut.setAttribute('Icon', 'hgIcon.ico') | |||
|
325 | shortcut.setAttribute('IconIndex', '0') | |||
|
326 | shortcut.setAttribute('Advertise', 'yes') | |||
|
327 | for k, v in sorted(metadata.items()): | |||
|
328 | shortcut.setAttribute(k, v) | |||
|
329 | ||||
|
330 | el.appendChild(shortcut) | |||
194 |
|
331 | |||
195 | return doc.toprettyxml() |
|
332 | return doc.toprettyxml() | |
196 |
|
333 | |||
@@ -249,9 +386,27 b' def build_installer(' | |||||
249 | post_build_fn(source_dir, hg_build_dir, dist_dir, version) |
|
386 | post_build_fn(source_dir, hg_build_dir, dist_dir, version) | |
250 |
|
387 | |||
251 | build_dir = hg_build_dir / ('wix-%s' % arch) |
|
388 | build_dir = hg_build_dir / ('wix-%s' % arch) | |
|
389 | staging_dir = build_dir / 'stage' | |||
252 |
|
390 | |||
253 | build_dir.mkdir(exist_ok=True) |
|
391 | build_dir.mkdir(exist_ok=True) | |
254 |
|
392 | |||
|
393 | # Purge the staging directory for every build so packaging is pristine. | |||
|
394 | if staging_dir.exists(): | |||
|
395 | print('purging %s' % staging_dir) | |||
|
396 | shutil.rmtree(staging_dir) | |||
|
397 | ||||
|
398 | stage_install(source_dir, staging_dir, lower_case=True) | |||
|
399 | ||||
|
400 | # We also install some extra files. | |||
|
401 | process_install_rules(EXTRA_INSTALL_RULES, source_dir, staging_dir) | |||
|
402 | ||||
|
403 | # And remove some files we don't want. | |||
|
404 | for f in STAGING_REMOVE_FILES: | |||
|
405 | p = staging_dir / f | |||
|
406 | if p.exists(): | |||
|
407 | print('removing %s' % p) | |||
|
408 | p.unlink() | |||
|
409 | ||||
255 | wix_pkg, wix_entry = download_entry('wix', hg_build_dir) |
|
410 | wix_pkg, wix_entry = download_entry('wix', hg_build_dir) | |
256 | wix_path = hg_build_dir / ('wix-%s' % wix_entry['version']) |
|
411 | wix_path = hg_build_dir / ('wix-%s' % wix_entry['version']) | |
257 |
|
412 | |||
@@ -264,25 +419,16 b' def build_installer(' | |||||
264 |
|
419 | |||
265 | defines = {'Platform': arch} |
|
420 | defines = {'Platform': arch} | |
266 |
|
421 | |||
267 | for wxs, rel_path in SUPPORT_WXS: |
|
422 | # Derive a .wxs file with the staged files. | |
268 |
|
|
423 | manifest_wxs = build_dir / 'stage.wxs' | |
269 | wxs_source_dir = source_dir / rel_path |
|
424 | with manifest_wxs.open('w', encoding='utf-8') as fh: | |
270 | run_candle(wix_path, build_dir, wxs, wxs_source_dir, defines=defines) |
|
425 | fh.write(make_files_xml(staging_dir, is_x64=arch == 'x64')) | |
|
426 | ||||
|
427 | run_candle(wix_path, build_dir, manifest_wxs, staging_dir, defines=defines) | |||
271 |
|
428 | |||
272 | for source, rel_path in sorted((extra_wxs or {}).items()): |
|
429 | for source, rel_path in sorted((extra_wxs or {}).items()): | |
273 | run_candle(wix_path, build_dir, source, rel_path, defines=defines) |
|
430 | run_candle(wix_path, build_dir, source, rel_path, defines=defines) | |
274 |
|
431 | |||
275 | # candle.exe doesn't like when we have an open handle on the file. |
|
|||
276 | # So use TemporaryDirectory() instead of NamedTemporaryFile(). |
|
|||
277 | with tempfile.TemporaryDirectory() as td: |
|
|||
278 | td = pathlib.Path(td) |
|
|||
279 |
|
||||
280 | tf = td / 'library.wxs' |
|
|||
281 | with tf.open('w') as fh: |
|
|||
282 | fh.write(make_libraries_xml(wix_dir, dist_dir)) |
|
|||
283 |
|
||||
284 | run_candle(wix_path, build_dir, tf, dist_dir, defines=defines) |
|
|||
285 |
|
||||
286 | source = wix_dir / 'mercurial.wxs' |
|
432 | source = wix_dir / 'mercurial.wxs' | |
287 | defines['Version'] = version |
|
433 | defines['Version'] = version | |
288 | defines['Comments'] = 'Installs Mercurial version %s' % version |
|
434 | defines['Comments'] = 'Installs Mercurial version %s' % version | |
@@ -308,20 +454,13 b' def build_installer(' | |||||
308 | str(msi_path), |
|
454 | str(msi_path), | |
309 | ] |
|
455 | ] | |
310 |
|
456 | |||
311 | for source, rel_path in SUPPORT_WXS: |
|
|||
312 | assert source.endswith('.wxs') |
|
|||
313 | args.append(str(build_dir / ('%s.wixobj' % source[:-4]))) |
|
|||
314 |
|
||||
315 | for source, rel_path in sorted((extra_wxs or {}).items()): |
|
457 | for source, rel_path in sorted((extra_wxs or {}).items()): | |
316 | assert source.endswith('.wxs') |
|
458 | assert source.endswith('.wxs') | |
317 | source = os.path.basename(source) |
|
459 | source = os.path.basename(source) | |
318 | args.append(str(build_dir / ('%s.wixobj' % source[:-4]))) |
|
460 | args.append(str(build_dir / ('%s.wixobj' % source[:-4]))) | |
319 |
|
461 | |||
320 | args.extend( |
|
462 | args.extend( | |
321 | [ |
|
463 | [str(build_dir / 'stage.wixobj'), str(build_dir / 'mercurial.wixobj'),] | |
322 | str(build_dir / 'library.wixobj'), |
|
|||
323 | str(build_dir / 'mercurial.wixobj'), |
|
|||
324 | ] |
|
|||
325 | ) |
|
464 | ) | |
326 |
|
465 | |||
327 | subprocess.run(args, cwd=str(source_dir), check=True) |
|
466 | subprocess.run(args, cwd=str(source_dir), check=True) |
@@ -1,21 +1,6 b'' | |||||
1 | ; Script generated by the Inno Setup Script Wizard. |
|
1 | ; Script generated by the Inno Setup Script Wizard. | |
2 | ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! |
|
2 | ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! | |
3 |
|
3 | |||
4 | #ifndef VERSION |
|
|||
5 | #define FileHandle |
|
|||
6 | #define FileLine |
|
|||
7 | #define VERSION = "unknown" |
|
|||
8 | #if FileHandle = FileOpen(SourcePath + "\..\..\..\mercurial\__version__.py") |
|
|||
9 | #expr FileLine = FileRead(FileHandle) |
|
|||
10 | #expr FileLine = FileRead(FileHandle) |
|
|||
11 | #define VERSION = Copy(FileLine, Pos('"', FileLine)+1, Len(FileLine)-Pos('"', FileLine)-1) |
|
|||
12 | #endif |
|
|||
13 | #if FileHandle |
|
|||
14 | #expr FileClose(FileHandle) |
|
|||
15 | #endif |
|
|||
16 | #pragma message "Detected Version: " + VERSION |
|
|||
17 | #endif |
|
|||
18 |
|
||||
19 | #ifndef ARCH |
|
4 | #ifndef ARCH | |
20 | #define ARCH = "x86" |
|
5 | #define ARCH = "x86" | |
21 | #endif |
|
6 | #endif | |
@@ -33,68 +18,40 b' ArchitecturesInstallIn64BitMode=x64' | |||||
33 | AppVerName=Mercurial {#VERSION} |
|
18 | AppVerName=Mercurial {#VERSION} | |
34 | OutputBaseFilename=Mercurial-{#VERSION} |
|
19 | OutputBaseFilename=Mercurial-{#VERSION} | |
35 | #endif |
|
20 | #endif | |
36 |
InfoAfterFile= |
|
21 | InfoAfterFile=../postinstall.txt | |
37 |
LicenseFile=C |
|
22 | LicenseFile=Copying.txt | |
38 | ShowLanguageDialog=yes |
|
23 | ShowLanguageDialog=yes | |
39 | AppPublisher=Matt Mackall and others |
|
24 | AppPublisher=Matt Mackall and others | |
40 | AppPublisherURL=https://mercurial-scm.org/ |
|
25 | AppPublisherURL=https://mercurial-scm.org/ | |
41 | AppSupportURL=https://mercurial-scm.org/ |
|
26 | AppSupportURL=https://mercurial-scm.org/ | |
42 | AppUpdatesURL=https://mercurial-scm.org/ |
|
27 | AppUpdatesURL=https://mercurial-scm.org/ | |
43 | AppID={{4B95A5F1-EF59-4B08-BED8-C891C46121B3} |
|
28 | {{ 'AppID={{4B95A5F1-EF59-4B08-BED8-C891C46121B3}' }} | |
44 | AppContact=mercurial@mercurial-scm.org |
|
29 | AppContact=mercurial@mercurial-scm.org | |
45 | DefaultDirName={pf}\Mercurial |
|
30 | DefaultDirName={pf}\Mercurial | |
46 |
SourceDir= |
|
31 | SourceDir=stage | |
47 | VersionInfoDescription=Mercurial distributed SCM (version {#VERSION}) |
|
32 | VersionInfoDescription=Mercurial distributed SCM (version {#VERSION}) | |
48 | VersionInfoCopyright=Copyright 2005-2019 Matt Mackall and others |
|
33 | VersionInfoCopyright=Copyright 2005-2019 Matt Mackall and others | |
49 | VersionInfoCompany=Matt Mackall and others |
|
34 | VersionInfoCompany=Matt Mackall and others | |
50 | InternalCompressLevel=max |
|
35 | InternalCompressLevel=max | |
51 | SolidCompression=true |
|
36 | SolidCompression=true | |
52 |
SetupIconFile= |
|
37 | SetupIconFile=../mercurial.ico | |
53 | AllowNoIcons=true |
|
38 | AllowNoIcons=true | |
54 | DefaultGroupName=Mercurial |
|
39 | DefaultGroupName=Mercurial | |
55 | PrivilegesRequired=none |
|
40 | PrivilegesRequired=none | |
56 | ChangesEnvironment=true |
|
41 | ChangesEnvironment=true | |
57 |
|
42 | |||
58 | [Files] |
|
43 | [Files] | |
59 | Source: contrib\mercurial.el; DestDir: {app}/Contrib |
|
44 | {% for entry in package_files -%} | |
60 | Source: contrib\vim\*.*; DestDir: {app}/Contrib/Vim |
|
45 | Source: {{ entry.source }}; DestDir: {{ entry.dest_dir }} | |
61 | Source: contrib\zsh_completion; DestDir: {app}/Contrib |
|
46 | {%- if entry.metadata %}; {{ entry.metadata }}{% endif %} | |
62 | Source: contrib\bash_completion; DestDir: {app}/Contrib |
|
47 | {% endfor %} | |
63 | Source: contrib\tcsh_completion; DestDir: {app}/Contrib |
|
|||
64 | Source: contrib\tcsh_completion_build.sh; DestDir: {app}/Contrib |
|
|||
65 | Source: contrib\hgk; DestDir: {app}/Contrib; DestName: hgk.tcl |
|
|||
66 | Source: contrib\xml.rnc; DestDir: {app}/Contrib |
|
|||
67 | Source: contrib\mercurial.el; DestDir: {app}/Contrib |
|
|||
68 | Source: contrib\mq.el; DestDir: {app}/Contrib |
|
|||
69 | Source: contrib\hgweb.fcgi; DestDir: {app}/Contrib |
|
|||
70 | Source: contrib\hgweb.wsgi; DestDir: {app}/Contrib |
|
|||
71 | Source: contrib\win32\ReadMe.html; DestDir: {app}; Flags: isreadme |
|
|||
72 | Source: contrib\win32\postinstall.txt; DestDir: {app}; DestName: ReleaseNotes.txt |
|
|||
73 | Source: dist\hg.exe; DestDir: {app}; AfterInstall: Touch('{app}\hg.exe.local') |
|
|||
74 | Source: dist\lib\*.dll; Destdir: {app}\lib |
|
|||
75 | Source: dist\lib\*.pyd; Destdir: {app}\lib |
|
|||
76 | Source: dist\python*.dll; Destdir: {app}; Flags: skipifsourcedoesntexist |
|
|||
77 | Source: dist\msvc*.dll; DestDir: {app}; Flags: skipifsourcedoesntexist |
|
|||
78 | Source: dist\Microsoft.VC*.CRT.manifest; DestDir: {app}; Flags: skipifsourcedoesntexist |
|
|||
79 | Source: dist\lib\library.zip; DestDir: {app}\lib |
|
|||
80 | Source: doc\*.html; DestDir: {app}\Docs |
|
|||
81 | Source: doc\style.css; DestDir: {app}\Docs |
|
|||
82 | Source: mercurial\help\*.txt; DestDir: {app}\help |
|
|||
83 | Source: mercurial\help\internals\*.txt; DestDir: {app}\help\internals |
|
|||
84 | Source: mercurial\default.d\*.rc; DestDir: {app}\default.d |
|
|||
85 | Source: mercurial\locale\*.*; DestDir: {app}\locale; Flags: recursesubdirs createallsubdirs skipifsourcedoesntexist |
|
|||
86 | Source: mercurial\templates\*.*; DestDir: {app}\Templates; Flags: recursesubdirs createallsubdirs |
|
|||
87 | Source: CONTRIBUTORS; DestDir: {app}; DestName: Contributors.txt |
|
|||
88 | Source: COPYING; DestDir: {app}; DestName: Copying.txt |
|
|||
89 |
|
48 | |||
90 | [INI] |
|
49 | [INI] | |
91 | Filename: {app}\Mercurial.url; Section: InternetShortcut; Key: URL; String: https://mercurial-scm.org/ |
|
50 | Filename: {app}\Mercurial.url; Section: InternetShortcut; Key: URL; String: https://mercurial-scm.org/ | |
92 | Filename: {app}\default.d\editor.rc; Section: ui; Key: editor; String: notepad |
|
|||
93 |
|
51 | |||
94 | [UninstallDelete] |
|
52 | [UninstallDelete] | |
95 | Type: files; Name: {app}\Mercurial.url |
|
53 | Type: files; Name: {app}\Mercurial.url | |
96 |
Type: filesandordirs; Name: {app}\ |
|
54 | Type: filesandordirs; Name: {app}\hgrc.d | |
97 | Type: files; Name: "{app}\hg.exe.local" |
|
|||
98 |
|
55 | |||
99 | [Icons] |
|
56 | [Icons] | |
100 | Name: {group}\Uninstall Mercurial; Filename: {uninstallexe} |
|
57 | Name: {group}\Uninstall Mercurial; Filename: {uninstallexe} | |
@@ -121,4 +78,5 b' begin' | |||||
121 | setArrayLength(Result, 1) |
|
78 | setArrayLength(Result, 1) | |
122 | Result[0] := ExpandConstant('{app}'); |
|
79 | Result[0] := ExpandConstant('{app}'); | |
123 | end; |
|
80 | end; | |
124 | #include "modpath.iss" |
|
81 | ||
|
82 | {% include 'modpath.iss' %} |
@@ -68,79 +68,42 b' begin' | |||||
68 | for d := 0 to GetArrayLength(pathdir)-1 do begin |
|
68 | for d := 0 to GetArrayLength(pathdir)-1 do begin | |
69 | updatepath := true; |
|
69 | updatepath := true; | |
70 |
|
70 | |||
71 | // Modify WinNT path |
|
71 | // Get current path, split into an array | |
72 | if UsingWinNT() = true then begin |
|
72 | RegQueryStringValue(regroot, regpath, 'Path', oldpath); | |
73 |
|
73 | oldpath := oldpath + ';'; | ||
74 | // Get current path, split into an array |
|
74 | i := 0; | |
75 | RegQueryStringValue(regroot, regpath, 'Path', oldpath); |
|
|||
76 | oldpath := oldpath + ';'; |
|
|||
77 | i := 0; |
|
|||
78 |
|
||||
79 | while (Pos(';', oldpath) > 0) do begin |
|
|||
80 | SetArrayLength(pathArr, i+1); |
|
|||
81 | pathArr[i] := Copy(oldpath, 0, Pos(';', oldpath)-1); |
|
|||
82 | oldpath := Copy(oldpath, Pos(';', oldpath)+1, Length(oldpath)); |
|
|||
83 | i := i + 1; |
|
|||
84 |
|
75 | |||
85 | // Check if current directory matches app dir |
|
76 | while (Pos(';', oldpath) > 0) do begin | |
86 | if pathdir[d] = pathArr[i-1] then begin |
|
77 | SetArrayLength(pathArr, i+1); | |
87 | // if uninstalling, remove dir from path |
|
78 | pathArr[i] := Copy(oldpath, 0, Pos(';', oldpath)-1); | |
88 | if IsUninstaller() = true then begin |
|
79 | oldpath := Copy(oldpath, Pos(';', oldpath)+1, Length(oldpath)); | |
89 | continue; |
|
80 | i := i + 1; | |
90 | // if installing, flag that dir already exists in path |
|
|||
91 | end else begin |
|
|||
92 | updatepath := false; |
|
|||
93 | end; |
|
|||
94 | end; |
|
|||
95 |
|
81 | |||
96 |
|
|
82 | // Check if current directory matches app dir | |
97 |
|
|
83 | if pathdir[d] = pathArr[i-1] then begin | |
98 | newpath := pathArr[i-1]; |
|
84 | // if uninstalling, remove dir from path | |
|
85 | if IsUninstaller() = true then begin | |||
|
86 | continue; | |||
|
87 | // if installing, flag that dir already exists in path | |||
99 | end else begin |
|
88 | end else begin | |
100 | newpath := newpath + ';' + pathArr[i-1]; |
|
89 | updatepath := false; | |
101 | end; |
|
90 | end; | |
102 | end; |
|
91 | end; | |
103 |
|
92 | |||
104 | // Append app dir to path if not already included |
|
93 | // Add current directory to new path | |
105 | if (IsUninstaller() = false) AND (updatepath = true) then |
|
94 | if i = 1 then begin | |
106 |
newpath := |
|
95 | newpath := pathArr[i-1]; | |
107 |
|
||||
108 | // Write new path |
|
|||
109 | RegWriteStringValue(regroot, regpath, 'Path', newpath); |
|
|||
110 |
|
||||
111 | // Modify Win9x path |
|
|||
112 | end else begin |
|
|||
113 |
|
||||
114 | // Convert to shortened dirname |
|
|||
115 | pathdir[d] := GetShortName(pathdir[d]); |
|
|||
116 |
|
||||
117 | // If autoexec.bat exists, check if app dir already exists in path |
|
|||
118 | aExecFile := 'C:\AUTOEXEC.BAT'; |
|
|||
119 | if FileExists(aExecFile) then begin |
|
|||
120 | LoadStringsFromFile(aExecFile, aExecArr); |
|
|||
121 | for i := 0 to GetArrayLength(aExecArr)-1 do begin |
|
|||
122 | if IsUninstaller() = false then begin |
|
|||
123 | // If app dir already exists while installing, skip add |
|
|||
124 | if (Pos(pathdir[d], aExecArr[i]) > 0) then |
|
|||
125 | updatepath := false; |
|
|||
126 | break; |
|
|||
127 | end else begin |
|
|||
128 | // If app dir exists and = what we originally set, then delete at uninstall |
|
|||
129 | if aExecArr[i] = 'SET PATH=%PATH%;' + pathdir[d] then |
|
|||
130 | aExecArr[i] := ''; |
|
|||
131 | end; |
|
|||
132 | end; |
|
|||
133 | end; |
|
|||
134 |
|
||||
135 | // If app dir not found, or autoexec.bat didn't exist, then (create and) append to current path |
|
|||
136 | if (IsUninstaller() = false) AND (updatepath = true) then begin |
|
|||
137 | SaveStringToFile(aExecFile, #13#10 + 'SET PATH=%PATH%;' + pathdir[d], True); |
|
|||
138 |
|
||||
139 | // If uninstalling, write the full autoexec out |
|
|||
140 | end else begin |
|
96 | end else begin | |
141 | SaveStringsToFile(aExecFile, aExecArr, False); |
|
97 | newpath := newpath + ';' + pathArr[i-1]; | |
142 | end; |
|
98 | end; | |
143 | end; |
|
99 | end; | |
|
100 | ||||
|
101 | // Append app dir to path if not already included | |||
|
102 | if (IsUninstaller() = false) AND (updatepath = true) then | |||
|
103 | newpath := newpath + ';' + pathdir[d]; | |||
|
104 | ||||
|
105 | // Write new path | |||
|
106 | RegWriteStringValue(regroot, regpath, 'Path', newpath); | |||
144 | end; |
|
107 | end; | |
145 | end; |
|
108 | end; | |
146 |
|
109 | |||
@@ -207,13 +170,6 b' begin' | |||||
207 | end; |
|
170 | end; | |
208 |
|
171 | |||
209 | function NeedRestart(): Boolean; |
|
172 | function NeedRestart(): Boolean; | |
210 | var |
|
|||
211 | taskname: String; |
|
|||
212 | begin |
|
173 | begin | |
213 | taskname := ModPathName; |
|
174 | Result := False; | |
214 | if IsTaskSelected(taskname) and not UsingWinNT() then begin |
|
|||
215 | Result := True; |
|
|||
216 | end else begin |
|
|||
217 | Result := False; |
|
|||
218 | end; |
|
|||
219 | end; |
|
175 | end; |
@@ -11,12 +11,12 b' The following system dependencies must b' | |||||
11 | * Inno Setup (http://jrsoftware.org/isdl.php) version 5.4 or newer. |
|
11 | * Inno Setup (http://jrsoftware.org/isdl.php) version 5.4 or newer. | |
12 | Be sure to install the optional Inno Setup Preprocessor feature, |
|
12 | Be sure to install the optional Inno Setup Preprocessor feature, | |
13 | which is required. |
|
13 | which is required. | |
14 |
* Python 3.5+ (to run the `` |
|
14 | * Python 3.5+ (to run the ``packaging.py`` script) | |
15 |
|
15 | |||
16 | Building |
|
16 | Building | |
17 | ======== |
|
17 | ======== | |
18 |
|
18 | |||
19 |
The `` |
|
19 | The ``packaging.py`` script automates the process of producing an | |
20 | Inno installer. It manages fetching and configuring the |
|
20 | Inno installer. It manages fetching and configuring the | |
21 | non-system dependencies (such as py2exe, gettext, and various |
|
21 | non-system dependencies (such as py2exe, gettext, and various | |
22 | Python packages). |
|
22 | Python packages). | |
@@ -31,11 +31,11 b' either ``Visual C++ 2008 32-bit Command ' | |||||
31 | From the prompt, change to the Mercurial source directory. e.g. |
|
31 | From the prompt, change to the Mercurial source directory. e.g. | |
32 | ``cd c:\src\hg``. |
|
32 | ``cd c:\src\hg``. | |
33 |
|
33 | |||
34 |
Next, invoke `` |
|
34 | Next, invoke ``packaging.py`` to produce an Inno installer. You will | |
35 | need to supply the path to the Python interpreter to use.:: |
|
35 | need to supply the path to the Python interpreter to use.:: | |
36 |
|
36 | |||
37 |
$ python3.exe contrib\packaging\ |
|
37 | $ python3.exe contrib\packaging\packaging.py \ | |
38 | --python c:\python27\python.exe |
|
38 | inno --python c:\python27\python.exe | |
39 |
|
39 | |||
40 | .. note:: |
|
40 | .. note:: | |
41 |
|
41 | |||
@@ -49,13 +49,13 b' configured into the ``build`` sub-direct' | |||||
49 | and an installer placed in the ``dist`` sub-directory. The final |
|
49 | and an installer placed in the ``dist`` sub-directory. The final | |
50 | line of output should print the name of the generated installer. |
|
50 | line of output should print the name of the generated installer. | |
51 |
|
51 | |||
52 |
Additional options may be configured. Run |
|
52 | Additional options may be configured. Run | |
53 | see a list of program flags. |
|
53 | ``packaging.py inno --help`` to see a list of program flags. | |
54 |
|
54 | |||
55 | MinGW |
|
55 | MinGW | |
56 | ===== |
|
56 | ===== | |
57 |
|
57 | |||
58 | It is theoretically possible to generate an installer that uses |
|
58 | It is theoretically possible to generate an installer that uses | |
59 |
MinGW. This isn't well tested and `` |
|
59 | MinGW. This isn't well tested and ``packaging.py`` and may properly | |
60 | support it. See old versions of this file in version control for |
|
60 | support it. See old versions of this file in version control for | |
61 | potentially useful hints as to how to achieve this. |
|
61 | potentially useful hints as to how to achieve this. |
@@ -8,65 +8,6 b' certifi==2019.9.11 \\' | |||||
8 | --hash=sha256:e4f3620cfea4f83eedc95b24abd9cd56f3c4b146dd0177e83a21b4eb49e21e50 \ |
|
8 | --hash=sha256:e4f3620cfea4f83eedc95b24abd9cd56f3c4b146dd0177e83a21b4eb49e21e50 \ | |
9 | --hash=sha256:fd7c7c74727ddcf00e9acd26bba8da604ffec95bf1c2144e67aff7a8b50e6cef \ |
|
9 | --hash=sha256:fd7c7c74727ddcf00e9acd26bba8da604ffec95bf1c2144e67aff7a8b50e6cef \ | |
10 | # via dulwich |
|
10 | # via dulwich | |
11 | cffi==1.13.1 \ |
|
|||
12 | --hash=sha256:00d890313797d9fe4420506613384b43099ad7d2b905c0752dbcc3a6f14d80fa \ |
|
|||
13 | --hash=sha256:0cf9e550ac6c5e57b713437e2f4ac2d7fd0cd10336525a27224f5fc1ec2ee59a \ |
|
|||
14 | --hash=sha256:0ea23c9c0cdd6778146a50d867d6405693ac3b80a68829966c98dd5e1bbae400 \ |
|
|||
15 | --hash=sha256:193697c2918ecdb3865acf6557cddf5076bb39f1f654975e087b67efdff83365 \ |
|
|||
16 | --hash=sha256:1ae14b542bf3b35e5229439c35653d2ef7d8316c1fffb980f9b7647e544baa98 \ |
|
|||
17 | --hash=sha256:1e389e069450609c6ffa37f21f40cce36f9be7643bbe5051ab1de99d5a779526 \ |
|
|||
18 | --hash=sha256:263242b6ace7f9cd4ea401428d2d45066b49a700852334fd55311bde36dcda14 \ |
|
|||
19 | --hash=sha256:33142ae9807665fa6511cfa9857132b2c3ee6ddffb012b3f0933fc11e1e830d5 \ |
|
|||
20 | --hash=sha256:364f8404034ae1b232335d8c7f7b57deac566f148f7222cef78cf8ae28ef764e \ |
|
|||
21 | --hash=sha256:47368f69fe6529f8f49a5d146ddee713fc9057e31d61e8b6dc86a6a5e38cecc1 \ |
|
|||
22 | --hash=sha256:4895640844f17bec32943995dc8c96989226974dfeb9dd121cc45d36e0d0c434 \ |
|
|||
23 | --hash=sha256:558b3afef987cf4b17abd849e7bedf64ee12b28175d564d05b628a0f9355599b \ |
|
|||
24 | --hash=sha256:5ba86e1d80d458b338bda676fd9f9d68cb4e7a03819632969cf6d46b01a26730 \ |
|
|||
25 | --hash=sha256:63424daa6955e6b4c70dc2755897f5be1d719eabe71b2625948b222775ed5c43 \ |
|
|||
26 | --hash=sha256:6381a7d8b1ebd0bc27c3bc85bc1bfadbb6e6f756b4d4db0aa1425c3719ba26b4 \ |
|
|||
27 | --hash=sha256:6381ab708158c4e1639da1f2a7679a9bbe3e5a776fc6d1fd808076f0e3145331 \ |
|
|||
28 | --hash=sha256:6fd58366747debfa5e6163ada468a90788411f10c92597d3b0a912d07e580c36 \ |
|
|||
29 | --hash=sha256:728ec653964655d65408949b07f9b2219df78badd601d6c49e28d604efe40599 \ |
|
|||
30 | --hash=sha256:7cfcfda59ef1f95b9f729c56fe8a4041899f96b72685d36ef16a3440a0f85da8 \ |
|
|||
31 | --hash=sha256:819f8d5197c2684524637f940445c06e003c4a541f9983fd30d6deaa2a5487d8 \ |
|
|||
32 | --hash=sha256:825ecffd9574557590e3225560a8a9d751f6ffe4a49e3c40918c9969b93395fa \ |
|
|||
33 | --hash=sha256:9009e917d8f5ef780c2626e29b6bc126f4cb2a4d43ca67aa2b40f2a5d6385e78 \ |
|
|||
34 | --hash=sha256:9c77564a51d4d914ed5af096cd9843d90c45b784b511723bd46a8a9d09cf16fc \ |
|
|||
35 | --hash=sha256:a19089fa74ed19c4fe96502a291cfdb89223a9705b1d73b3005df4256976142e \ |
|
|||
36 | --hash=sha256:a40ed527bffa2b7ebe07acc5a3f782da072e262ca994b4f2085100b5a444bbb2 \ |
|
|||
37 | --hash=sha256:bb75ba21d5716abc41af16eac1145ab2e471deedde1f22c6f99bd9f995504df0 \ |
|
|||
38 | --hash=sha256:e22a00c0c81ffcecaf07c2bfb3672fa372c50e2bd1024ffee0da191c1b27fc71 \ |
|
|||
39 | --hash=sha256:e55b5a746fb77f10c83e8af081979351722f6ea48facea79d470b3731c7b2891 \ |
|
|||
40 | --hash=sha256:ec2fa3ee81707a5232bf2dfbd6623fdb278e070d596effc7e2d788f2ada71a05 \ |
|
|||
41 | --hash=sha256:fd82eb4694be712fcae03c717ca2e0fc720657ac226b80bbb597e971fc6928c2 \ |
|
|||
42 | # via cryptography |
|
|||
43 | configparser==4.0.2 \ |
|
|||
44 | --hash=sha256:254c1d9c79f60c45dfde850850883d5aaa7f19a23f13561243a050d5a7c3fe4c \ |
|
|||
45 | --hash=sha256:c7d282687a5308319bf3d2e7706e575c635b0a470342641c93bea0ea3b5331df \ |
|
|||
46 | # via entrypoints |
|
|||
47 | cryptography==2.8 \ |
|
|||
48 | --hash=sha256:02079a6addc7b5140ba0825f542c0869ff4df9a69c360e339ecead5baefa843c \ |
|
|||
49 | --hash=sha256:1df22371fbf2004c6f64e927668734070a8953362cd8370ddd336774d6743595 \ |
|
|||
50 | --hash=sha256:369d2346db5934345787451504853ad9d342d7f721ae82d098083e1f49a582ad \ |
|
|||
51 | --hash=sha256:3cda1f0ed8747339bbdf71b9f38ca74c7b592f24f65cdb3ab3765e4b02871651 \ |
|
|||
52 | --hash=sha256:44ff04138935882fef7c686878e1c8fd80a723161ad6a98da31e14b7553170c2 \ |
|
|||
53 | --hash=sha256:4b1030728872c59687badcca1e225a9103440e467c17d6d1730ab3d2d64bfeff \ |
|
|||
54 | --hash=sha256:58363dbd966afb4f89b3b11dfb8ff200058fbc3b947507675c19ceb46104b48d \ |
|
|||
55 | --hash=sha256:6ec280fb24d27e3d97aa731e16207d58bd8ae94ef6eab97249a2afe4ba643d42 \ |
|
|||
56 | --hash=sha256:7270a6c29199adc1297776937a05b59720e8a782531f1f122f2eb8467f9aab4d \ |
|
|||
57 | --hash=sha256:73fd30c57fa2d0a1d7a49c561c40c2f79c7d6c374cc7750e9ac7c99176f6428e \ |
|
|||
58 | --hash=sha256:7f09806ed4fbea8f51585231ba742b58cbcfbfe823ea197d8c89a5e433c7e912 \ |
|
|||
59 | --hash=sha256:90df0cc93e1f8d2fba8365fb59a858f51a11a394d64dbf3ef844f783844cc793 \ |
|
|||
60 | --hash=sha256:971221ed40f058f5662a604bd1ae6e4521d84e6cad0b7b170564cc34169c8f13 \ |
|
|||
61 | --hash=sha256:a518c153a2b5ed6b8cc03f7ae79d5ffad7315ad4569b2d5333a13c38d64bd8d7 \ |
|
|||
62 | --hash=sha256:b0de590a8b0979649ebeef8bb9f54394d3a41f66c5584fff4220901739b6b2f0 \ |
|
|||
63 | --hash=sha256:b43f53f29816ba1db8525f006fa6f49292e9b029554b3eb56a189a70f2a40879 \ |
|
|||
64 | --hash=sha256:d31402aad60ed889c7e57934a03477b572a03af7794fa8fb1780f21ea8f6551f \ |
|
|||
65 | --hash=sha256:de96157ec73458a7f14e3d26f17f8128c959084931e8997b9e655a39c8fde9f9 \ |
|
|||
66 | --hash=sha256:df6b4dca2e11865e6cfbfb708e800efb18370f5a46fd601d3755bc7f85b3a8a2 \ |
|
|||
67 | --hash=sha256:ecadccc7ba52193963c0475ac9f6fa28ac01e01349a2ca48509667ef41ffd2cf \ |
|
|||
68 | --hash=sha256:fb81c17e0ebe3358486cd8cc3ad78adbae58af12fc2bf2bc0bb84e8090fa5ce8 \ |
|
|||
69 | # via secretstorage |
|
|||
70 | docutils==0.15.2 \ |
|
11 | docutils==0.15.2 \ | |
71 | --hash=sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0 \ |
|
12 | --hash=sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0 \ | |
72 | --hash=sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827 \ |
|
13 | --hash=sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827 \ | |
@@ -85,35 +26,16 b' entrypoints==0.3 \\' | |||||
85 | --hash=sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19 \ |
|
26 | --hash=sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19 \ | |
86 | --hash=sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451 \ |
|
27 | --hash=sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451 \ | |
87 | # via keyring |
|
28 | # via keyring | |
88 | enum34==1.1.6 \ |
|
|||
89 | --hash=sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850 \ |
|
|||
90 | --hash=sha256:644837f692e5f550741432dd3f223bbb9852018674981b1664e5dc339387588a \ |
|
|||
91 | --hash=sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79 \ |
|
|||
92 | --hash=sha256:8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1 \ |
|
|||
93 | # via cryptography |
|
|||
94 | ipaddress==1.0.23 \ |
|
|||
95 | --hash=sha256:6e0f4a39e66cb5bb9a137b00276a2eff74f93b71dcbdad6f10ff7df9d3557fcc \ |
|
|||
96 | --hash=sha256:b7f8e0369580bb4a24d5ba1d7cc29660a4a6987763faf1d8a8046830e020e7e2 \ |
|
|||
97 | # via cryptography |
|
|||
98 | keyring==18.0.1 \ |
|
29 | keyring==18.0.1 \ | |
99 | --hash=sha256:67d6cc0132bd77922725fae9f18366bb314fd8f95ff4d323a4df41890a96a838 \ |
|
30 | --hash=sha256:67d6cc0132bd77922725fae9f18366bb314fd8f95ff4d323a4df41890a96a838 \ | |
100 | --hash=sha256:7b29ebfcf8678c4da531b2478a912eea01e80007e5ddca9ee0c7038cb3489ec6 |
|
31 | --hash=sha256:7b29ebfcf8678c4da531b2478a912eea01e80007e5ddca9ee0c7038cb3489ec6 | |
101 | pycparser==2.19 \ |
|
|||
102 | --hash=sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3 \ |
|
|||
103 | # via cffi |
|
|||
104 | pygments==2.4.2 \ |
|
32 | pygments==2.4.2 \ | |
105 | --hash=sha256:71e430bc85c88a430f000ac1d9b331d2407f681d6f6aec95e8bcfbc3df5b0127 \ |
|
33 | --hash=sha256:71e430bc85c88a430f000ac1d9b331d2407f681d6f6aec95e8bcfbc3df5b0127 \ | |
106 | --hash=sha256:881c4c157e45f30af185c1ffe8d549d48ac9127433f2c380c24b84572ad66297 |
|
34 | --hash=sha256:881c4c157e45f30af185c1ffe8d549d48ac9127433f2c380c24b84572ad66297 | |
107 | pywin32-ctypes==0.2.0 \ |
|
35 | pywin32-ctypes==0.2.0 \ | |
108 | --hash=sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942 \ |
|
36 | --hash=sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942 \ | |
109 | --hash=sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98 |
|
37 | --hash=sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98 \ | |
110 | secretstorage==2.3.1 \ |
|
|||
111 | --hash=sha256:3af65c87765323e6f64c83575b05393f9e003431959c9395d1791d51497f29b6 \ |
|
|||
112 | # via keyring |
|
38 | # via keyring | |
113 | six==1.12.0 \ |
|
|||
114 | --hash=sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c \ |
|
|||
115 | --hash=sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73 \ |
|
|||
116 | # via cryptography |
|
|||
117 | urllib3==1.25.6 \ |
|
39 | urllib3==1.25.6 \ | |
118 | --hash=sha256:3de946ffbed6e6746608990594d08faac602528ac7015ac28d33cee6a45b7398 \ |
|
40 | --hash=sha256:3de946ffbed6e6746608990594d08faac602528ac7015ac28d33cee6a45b7398 \ | |
119 | --hash=sha256:9a107b99a5393caf59c7aa3c1249c16e6879447533d0887f4336dde834c7be86 \ |
|
41 | --hash=sha256:9a107b99a5393caf59c7aa3c1249c16e6879447533d0887f4336dde834c7be86 \ |
@@ -4,49 +4,9 b'' | |||||
4 | and replace 'Mercurial' in this notice with the name of |
|
4 | and replace 'Mercurial' in this notice with the name of | |
5 | your project. Component GUIDs have global namespace! --> |
|
5 | your project. Component GUIDs have global namespace! --> | |
6 |
|
6 | |||
7 | <!-- contrib.wxs --> |
|
|||
8 | <?define contrib.guid = {4E11FFC2-E2F7-482A-8460-9394B5489F02} ?> |
|
|||
9 | <?define contrib.vim.guid = {BB04903A-652D-4C4F-9590-2BD07A2304F2} ?> |
|
|||
10 |
|
||||
11 | <!-- dist.wxs --> |
|
|||
12 | <?define dist.guid = {CE405FE6-CD1E-4873-9C9A-7683AE5A3D90} ?> |
|
|||
13 | <?define lib.guid = {877633b5-0b7e-4b46-8f1c-224a61733297} ?> |
|
|||
14 |
|
||||
15 | <!-- doc.wxs --> |
|
|||
16 | <?define doc.hg.1.html.guid = {AAAA3FDA-EDC5-4220-B59D-D342722358A2} ?> |
|
|||
17 | <?define doc.hgignore.5.html.guid = {AA9118C4-F3A0-4429-A5F4-5A1906B2D67F} ?> |
|
|||
18 | <?define doc.hgrc.5.html = {E0CEA1EB-FA01-408c-844B-EE5965165BAE} ?> |
|
|||
19 | <?define doc.style.css = {172F8262-98E0-4711-BD39-4DAE0D77EF05} ?> |
|
|||
20 |
|
||||
21 | <!-- help.wxs --> |
|
|||
22 | <?define help.root.guid = {9FA957DB-6DFE-44f2-AD03-293B2791CF17} ?> |
|
|||
23 | <?define help.internals.guid = {2DD7669D-0DB8-4C39-9806-78E6475E7ACC} ?> |
|
|||
24 |
|
||||
25 | <!-- i18n.wxs --> |
|
|||
26 | <?define i18nFolder.guid = {1BF8026D-CF7C-4174-AEE6-D6B7BF119248} ?> |
|
|||
27 |
|
||||
28 | <!-- templates.wxs --> |
|
|||
29 | <?define templates.root.guid = {437FD55C-7756-4EA0-87E5-FDBE75DC8595} ?> |
|
|||
30 | <?define templates.atom.guid = {D30E14A5-8AF0-4268-8B00-00BEE9E09E39} ?> |
|
|||
31 | <?define templates.coal.guid = {B63CCAAB-4EAF-43b4-901E-4BD13F5B78FC} ?> |
|
|||
32 | <?define templates.gitweb.guid = {827334AF-1EFD-421B-962C-5660A068F612} ?> |
|
|||
33 | <?define templates.json.guid = {F535BE7A-EC34-46E0-B9BE-013F3DBAFB19} ?> |
|
|||
34 | <?define templates.monoblue.guid = {8060A1E4-BD4C-453E-92CB-9536DC44A9E3} ?> |
|
|||
35 | <?define templates.paper.guid = {61AB1DE9-645F-46ED-8AF8-0CF02267FFBB} ?> |
|
|||
36 | <?define templates.raw.guid = {834DF8D7-9784-43A6-851D-A96CE1B3575B} ?> |
|
|||
37 | <?define templates.rss.guid = {9338FA09-E128-4B1C-B723-1142DBD09E14} ?> |
|
|||
38 | <?define templates.spartan.guid = {80222625-FA8F-44b1-86CE-1781EF375D09} ?> |
|
|||
39 | <?define templates.static.guid = {6B3D7C24-98DA-4B67-9F18-35F77357B0B4} ?> |
|
|||
40 |
|
||||
41 | <!-- mercurial.wxs --> |
|
7 | <!-- mercurial.wxs --> | |
42 | <?define ProductUpgradeCode = {A1CC6134-E945-4399-BE36-EB0017FDF7CF} ?> |
|
8 | <?define ProductUpgradeCode = {A1CC6134-E945-4399-BE36-EB0017FDF7CF} ?> | |
43 |
|
||||
44 | <?define ComponentMainExecutableGUID = {D102B8FA-059B-4ACC-9FA3-8C78C3B58EEF} ?> |
|
9 | <?define ComponentMainExecutableGUID = {D102B8FA-059B-4ACC-9FA3-8C78C3B58EEF} ?> | |
45 |
|
||||
46 | <?define ReadMe.guid = {56A8E372-991D-4DCA-B91D-93D775974CF5} ?> |
|
|||
47 | <?define COPYING.guid = {B7801DBA-1C49-4BF4-91AD-33C65F5C7895} ?> |
|
|||
48 | <?define mercurial.rc.guid = {1D5FAEEE-7E6E-43B1-9F7F-802714316B15} ?> |
|
|||
49 | <?define mergetools.rc.guid = {E8A1DC29-FF40-4B5F-BD12-80B9F7BF0CCD} ?> |
|
|||
50 | <?define ProgramMenuDir.guid = {D5A63320-1238-489B-B68B-CF053E9577CA} ?> |
|
10 | <?define ProgramMenuDir.guid = {D5A63320-1238-489B-B68B-CF053E9577CA} ?> | |
51 |
|
11 | |||
52 | </Include> |
|
12 | </Include> |
@@ -60,30 +60,10 b'' | |||||
60 | <Directory Id='$(var.PFolder)' Name='PFiles'> |
|
60 | <Directory Id='$(var.PFolder)' Name='PFiles'> | |
61 | <Directory Id='INSTALLDIR' Name='Mercurial'> |
|
61 | <Directory Id='INSTALLDIR' Name='Mercurial'> | |
62 | <Component Id='MainExecutable' Guid='$(var.ComponentMainExecutableGUID)' Win64='$(var.IsX64)'> |
|
62 | <Component Id='MainExecutable' Guid='$(var.ComponentMainExecutableGUID)' Win64='$(var.IsX64)'> | |
63 | <File Id='hgEXE' Name='hg.exe' Source='dist\hg.exe' KeyPath='yes' /> |
|
63 | <CreateFolder /> | |
64 | <Environment Id="Environment" Name="PATH" Part="last" System="yes" |
|
64 | <Environment Id="Environment" Name="PATH" Part="last" System="yes" | |
65 | Permanent="no" Value="[INSTALLDIR]" Action="set" /> |
|
65 | Permanent="no" Value="[INSTALLDIR]" Action="set" /> | |
66 | </Component> |
|
66 | </Component> | |
67 | <Component Id='ReadMe' Guid='$(var.ReadMe.guid)' Win64='$(var.IsX64)'> |
|
|||
68 | <File Id='ReadMe' Name='ReadMe.html' Source='contrib\win32\ReadMe.html' |
|
|||
69 | KeyPath='yes'/> |
|
|||
70 | </Component> |
|
|||
71 | <Component Id='COPYING' Guid='$(var.COPYING.guid)' Win64='$(var.IsX64)'> |
|
|||
72 | <File Id='COPYING' Name='COPYING.rtf' Source='contrib\packaging\wix\COPYING.rtf' |
|
|||
73 | KeyPath='yes'/> |
|
|||
74 | </Component> |
|
|||
75 |
|
||||
76 | <Directory Id='HGRCD' Name='hgrc.d'> |
|
|||
77 | <Component Id='mercurial.rc' Guid='$(var.mercurial.rc.guid)' Win64='$(var.IsX64)'> |
|
|||
78 | <File Id='mercurial.rc' Name='Mercurial.rc' Source='contrib\win32\mercurial.ini' |
|
|||
79 | ReadOnly='yes' KeyPath='yes'/> |
|
|||
80 | </Component> |
|
|||
81 | <Component Id='mergetools.rc' Guid='$(var.mergetools.rc.guid)' Win64='$(var.IsX64)'> |
|
|||
82 | <File Id='mergetools.rc' Name='MergeTools.rc' Source='mercurial\default.d\mergetools.rc' |
|
|||
83 | ReadOnly='yes' KeyPath='yes'/> |
|
|||
84 | </Component> |
|
|||
85 | </Directory> |
|
|||
86 |
|
||||
87 | </Directory> |
|
67 | </Directory> | |
88 | </Directory> |
|
68 | </Directory> | |
89 |
|
69 | |||
@@ -117,15 +97,12 b'' | |||||
117 | <Feature Id='MainProgram' Title='Program' Description='Mercurial command line app' |
|
97 | <Feature Id='MainProgram' Title='Program' Description='Mercurial command line app' | |
118 | Level='1' Absent='disallow' > |
|
98 | Level='1' Absent='disallow' > | |
119 | <ComponentRef Id='MainExecutable' /> |
|
99 | <ComponentRef Id='MainExecutable' /> | |
120 | <ComponentRef Id='distOutput' /> |
|
|||
121 | <ComponentRef Id='libOutput' /> |
|
|||
122 | <ComponentRef Id='ProgramMenuDir' /> |
|
100 | <ComponentRef Id='ProgramMenuDir' /> | |
123 |
<ComponentRef Id= |
|
101 | <ComponentGroupRef Id="hg.group.ROOT" /> | |
124 |
<ComponentRef Id= |
|
102 | <ComponentGroupRef Id="hg.group.hgrc.d" /> | |
125 |
<ComponentRef Id= |
|
103 | <ComponentGroupRef Id="hg.group.helptext" /> | |
126 |
<ComponentRef Id= |
|
104 | <ComponentGroupRef Id="hg.group.lib" /> | |
127 |
<ComponentGroupRef Id= |
|
105 | <ComponentGroupRef Id="hg.group.templates" /> | |
128 | <ComponentGroupRef Id='templatesFolder' /> |
|
|||
129 | <MergeRef Id='VCRuntime' /> |
|
106 | <MergeRef Id='VCRuntime' /> | |
130 | <MergeRef Id='VCRuntimePolicy' /> |
|
107 | <MergeRef Id='VCRuntimePolicy' /> | |
131 | </Feature> |
|
108 | </Feature> | |
@@ -135,14 +112,13 b'' | |||||
135 | <?endforeach?> |
|
112 | <?endforeach?> | |
136 | <?endif?> |
|
113 | <?endif?> | |
137 | <Feature Id='Locales' Title='Translations' Description='Translations' Level='1'> |
|
114 | <Feature Id='Locales' Title='Translations' Description='Translations' Level='1'> | |
138 |
<ComponentGroupRef Id= |
|
115 | <ComponentGroupRef Id="hg.group.locale" /> | |
139 | <ComponentRef Id='i18nFolder' /> |
|
|||
140 | </Feature> |
|
116 | </Feature> | |
141 | <Feature Id='Documentation' Title='Documentation' Description='HTML man pages' Level='1'> |
|
117 | <Feature Id='Documentation' Title='Documentation' Description='HTML man pages' Level='1'> | |
142 |
<ComponentGroupRef Id= |
|
118 | <ComponentGroupRef Id="hg.group.doc" /> | |
143 | </Feature> |
|
119 | </Feature> | |
144 | <Feature Id='Misc' Title='Miscellaneous' Description='Contributed scripts' Level='1'> |
|
120 | <Feature Id='Misc' Title='Miscellaneous' Description='Contributed scripts' Level='1'> | |
145 |
<ComponentGroupRef Id= |
|
121 | <ComponentGroupRef Id="hg.group.contrib" /> | |
146 | </Feature> |
|
122 | </Feature> | |
147 | </Feature> |
|
123 | </Feature> | |
148 |
|
124 |
@@ -18,12 +18,12 b' dependencies must be installed:' | |||||
18 | * Python 2.7 (download from https://www.python.org/downloads/) |
|
18 | * Python 2.7 (download from https://www.python.org/downloads/) | |
19 | * Microsoft Visual C++ Compiler for Python 2.7 |
|
19 | * Microsoft Visual C++ Compiler for Python 2.7 | |
20 | (https://www.microsoft.com/en-us/download/details.aspx?id=44266) |
|
20 | (https://www.microsoft.com/en-us/download/details.aspx?id=44266) | |
21 |
* Python 3.5+ (to run the `` |
|
21 | * Python 3.5+ (to run the ``packaging.py`` script) | |
22 |
|
22 | |||
23 | Building |
|
23 | Building | |
24 | ======== |
|
24 | ======== | |
25 |
|
25 | |||
26 |
The `` |
|
26 | The ``packaging.py`` script automates the process of producing an MSI | |
27 | installer. It manages fetching and configuring non-system dependencies |
|
27 | installer. It manages fetching and configuring non-system dependencies | |
28 | (such as py2exe, gettext, and various Python packages). |
|
28 | (such as py2exe, gettext, and various Python packages). | |
29 |
|
29 | |||
@@ -37,11 +37,11 b' launch either ``Visual C++ 2008 32-bit C' | |||||
37 | From the prompt, change to the Mercurial source directory. e.g. |
|
37 | From the prompt, change to the Mercurial source directory. e.g. | |
38 | ``cd c:\src\hg``. |
|
38 | ``cd c:\src\hg``. | |
39 |
|
39 | |||
40 |
Next, invoke `` |
|
40 | Next, invoke ``packaging.py`` to produce an MSI installer. You will need | |
41 | to supply the path to the Python interpreter to use.:: |
|
41 | to supply the path to the Python interpreter to use.:: | |
42 |
|
42 | |||
43 |
$ python3 contrib\packaging\ |
|
43 | $ python3 contrib\packaging\packaging.py \ | |
44 | --python c:\python27\python.exe |
|
44 | wix --python c:\python27\python.exe | |
45 |
|
45 | |||
46 | .. note:: |
|
46 | .. note:: | |
47 |
|
47 | |||
@@ -54,8 +54,8 b' configured into the ``build`` sub-direct' | |||||
54 | and an installer placed in the ``dist`` sub-directory. The final line |
|
54 | and an installer placed in the ``dist`` sub-directory. The final line | |
55 | of output should print the name of the generated installer. |
|
55 | of output should print the name of the generated installer. | |
56 |
|
56 | |||
57 |
Additional options may be configured. Run `` |
|
57 | Additional options may be configured. Run ``packaging.py wix --help`` to | |
58 | a list of program flags. |
|
58 | see a list of program flags. | |
59 |
|
59 | |||
60 | Relationship to TortoiseHG |
|
60 | Relationship to TortoiseHG | |
61 | ========================== |
|
61 | ========================== |
@@ -1,13 +1,13 b'' | |||||
1 |
# |
|
1 | # | |
2 |
# This file is autogenerated by pip-compile |
|
2 | # This file is autogenerated by pip-compile | |
3 |
# To update, run: |
|
3 | # To update, run: | |
4 |
# |
|
4 | # | |
5 |
# pip-compile --generate-hashes --output-file=contrib/packaging/wix/requirements.txt contrib/packaging/wix/requirements.txt.in |
|
5 | # pip-compile --generate-hashes --output-file=contrib/packaging/wix/requirements.txt contrib/packaging/wix/requirements.txt.in | |
6 |
# |
|
6 | # | |
7 |
docutils==0.15.2 \ |
|
7 | docutils==0.15.2 \ | |
8 |
--hash=sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0 \ |
|
8 | --hash=sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0 \ | |
9 |
--hash=sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827 \ |
|
9 | --hash=sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827 \ | |
10 |
--hash=sha256:a2aeea129088da402665e92e0b25b04b073c04b2dce4ab65caaa38b7ce2e1a99 |
|
10 | --hash=sha256:a2aeea129088da402665e92e0b25b04b073c04b2dce4ab65caaa38b7ce2e1a99 | |
11 |
pygments==2.4.2 \ |
|
11 | pygments==2.4.2 \ | |
12 |
--hash=sha256:71e430bc85c88a430f000ac1d9b331d2407f681d6f6aec95e8bcfbc3df5b0127 \ |
|
12 | --hash=sha256:71e430bc85c88a430f000ac1d9b331d2407f681d6f6aec95e8bcfbc3df5b0127 \ | |
13 |
--hash=sha256:881c4c157e45f30af185c1ffe8d549d48ac9127433f2c380c24b84572ad66297 |
|
13 | --hash=sha256:881c4c157e45f30af185c1ffe8d549d48ac9127433f2c380c24b84572ad66297 |
@@ -726,8 +726,8 b' def clearfilecache(obj, attrname):' | |||||
726 |
|
726 | |||
727 | def clearchangelog(repo): |
|
727 | def clearchangelog(repo): | |
728 | if repo is not repo.unfiltered(): |
|
728 | if repo is not repo.unfiltered(): | |
729 |
object.__setattr__(repo, |
|
729 | object.__setattr__(repo, '_clcachekey', None) | |
730 |
object.__setattr__(repo, |
|
730 | object.__setattr__(repo, '_clcache', None) | |
731 | clearfilecache(repo.unfiltered(), 'changelog') |
|
731 | clearfilecache(repo.unfiltered(), 'changelog') | |
732 |
|
732 | |||
733 |
|
733 | |||
@@ -760,7 +760,10 b' def perfannotate(ui, repo, f, **opts):' | |||||
760 |
|
760 | |||
761 | @command( |
|
761 | @command( | |
762 | b'perfstatus', |
|
762 | b'perfstatus', | |
763 | [(b'u', b'unknown', False, b'ask status to look for unknown files')] |
|
763 | [ | |
|
764 | (b'u', b'unknown', False, b'ask status to look for unknown files'), | |||
|
765 | (b'', b'dirstate', False, b'benchmark the internal dirstate call'), | |||
|
766 | ] | |||
764 | + formatteropts, |
|
767 | + formatteropts, | |
765 | ) |
|
768 | ) | |
766 | def perfstatus(ui, repo, **opts): |
|
769 | def perfstatus(ui, repo, **opts): | |
@@ -776,7 +779,20 b' def perfstatus(ui, repo, **opts):' | |||||
776 | # timer(lambda: sum(map(len, repo.dirstate.status(m, [], False, False, |
|
779 | # timer(lambda: sum(map(len, repo.dirstate.status(m, [], False, False, | |
777 | # False)))) |
|
780 | # False)))) | |
778 | timer, fm = gettimer(ui, opts) |
|
781 | timer, fm = gettimer(ui, opts) | |
779 | timer(lambda: sum(map(len, repo.status(unknown=opts[b'unknown'])))) |
|
782 | if opts[b'dirstate']: | |
|
783 | dirstate = repo.dirstate | |||
|
784 | m = scmutil.matchall(repo) | |||
|
785 | unknown = opts[b'unknown'] | |||
|
786 | ||||
|
787 | def status_dirstate(): | |||
|
788 | s = dirstate.status( | |||
|
789 | m, subrepos=[], ignored=False, clean=False, unknown=unknown | |||
|
790 | ) | |||
|
791 | sum(map(bool, s)) | |||
|
792 | ||||
|
793 | timer(status_dirstate) | |||
|
794 | else: | |||
|
795 | timer(lambda: sum(map(len, repo.status(unknown=opts[b'unknown'])))) | |||
780 | fm.end() |
|
796 | fm.end() | |
781 |
|
797 | |||
782 |
|
798 | |||
@@ -804,6 +820,7 b' def clearcaches(cl):' | |||||
804 | if util.safehasattr(cl, b'clearcaches'): |
|
820 | if util.safehasattr(cl, b'clearcaches'): | |
805 | cl.clearcaches() |
|
821 | cl.clearcaches() | |
806 | elif util.safehasattr(cl, b'_nodecache'): |
|
822 | elif util.safehasattr(cl, b'_nodecache'): | |
|
823 | # <= hg-5.2 | |||
807 | from mercurial.node import nullid, nullrev |
|
824 | from mercurial.node import nullid, nullrev | |
808 |
|
825 | |||
809 | cl._nodecache = {nullid: nullrev} |
|
826 | cl._nodecache = {nullid: nullrev} | |
@@ -1404,13 +1421,15 b' def perfphasesremote(ui, repo, dest=None' | |||||
1404 | else: |
|
1421 | else: | |
1405 | ui.statusnoi18n(b'publishing: no\n') |
|
1422 | ui.statusnoi18n(b'publishing: no\n') | |
1406 |
|
1423 | |||
1407 |
node |
|
1424 | has_node = getattr(repo.changelog.index, 'has_node', None) | |
|
1425 | if has_node is None: | |||
|
1426 | has_node = repo.changelog.nodemap.__contains__ | |||
1408 | nonpublishroots = 0 |
|
1427 | nonpublishroots = 0 | |
1409 | for nhex, phase in remotephases.iteritems(): |
|
1428 | for nhex, phase in remotephases.iteritems(): | |
1410 | if nhex == b'publishing': # ignore data related to publish option |
|
1429 | if nhex == b'publishing': # ignore data related to publish option | |
1411 | continue |
|
1430 | continue | |
1412 | node = bin(nhex) |
|
1431 | node = bin(nhex) | |
1413 |
if node |
|
1432 | if has_node(node) and int(phase): | |
1414 | nonpublishroots += 1 |
|
1433 | nonpublishroots += 1 | |
1415 | ui.statusnoi18n(b'number of roots: %d\n' % len(remotephases)) |
|
1434 | ui.statusnoi18n(b'number of roots: %d\n' % len(remotephases)) | |
1416 | ui.statusnoi18n(b'number of known non public roots: %d\n' % nonpublishroots) |
|
1435 | ui.statusnoi18n(b'number of known non public roots: %d\n' % nonpublishroots) | |
@@ -1610,7 +1629,11 b' def perfnodemap(ui, repo, **opts):' | |||||
1610 | def setnodeget(): |
|
1629 | def setnodeget(): | |
1611 | # probably not necessary, but for good measure |
|
1630 | # probably not necessary, but for good measure | |
1612 | clearchangelog(unfi) |
|
1631 | clearchangelog(unfi) | |
1613 |
|
|
1632 | cl = makecl(unfi) | |
|
1633 | if util.safehasattr(cl.index, 'get_rev'): | |||
|
1634 | nodeget[0] = cl.index.get_rev | |||
|
1635 | else: | |||
|
1636 | nodeget[0] = cl.nodemap.get | |||
1614 |
|
1637 | |||
1615 | def d(): |
|
1638 | def d(): | |
1616 | get = nodeget[0] |
|
1639 | get = nodeget[0] | |
@@ -1636,13 +1659,13 b' def perfstartup(ui, repo, **opts):' | |||||
1636 | timer, fm = gettimer(ui, opts) |
|
1659 | timer, fm = gettimer(ui, opts) | |
1637 |
|
1660 | |||
1638 | def d(): |
|
1661 | def d(): | |
1639 |
if os.name != |
|
1662 | if os.name != 'nt': | |
1640 | os.system( |
|
1663 | os.system( | |
1641 | b"HGRCPATH= %s version -q > /dev/null" % fsencode(sys.argv[0]) |
|
1664 | b"HGRCPATH= %s version -q > /dev/null" % fsencode(sys.argv[0]) | |
1642 | ) |
|
1665 | ) | |
1643 | else: |
|
1666 | else: | |
1644 |
os.environ[ |
|
1667 | os.environ['HGRCPATH'] = r' ' | |
1645 |
os.system( |
|
1668 | os.system("%s version -q > NUL" % sys.argv[0]) | |
1646 |
|
1669 | |||
1647 | timer(d) |
|
1670 | timer(d) | |
1648 | fm.end() |
|
1671 | fm.end() | |
@@ -1828,7 +1851,7 b' def perftemplating(ui, repo, testedtempl' | |||||
1828 | opts = _byteskwargs(opts) |
|
1851 | opts = _byteskwargs(opts) | |
1829 |
|
1852 | |||
1830 | nullui = ui.copy() |
|
1853 | nullui = ui.copy() | |
1831 |
nullui.fout = open(os.devnull, |
|
1854 | nullui.fout = open(os.devnull, 'wb') | |
1832 | nullui.disablepager() |
|
1855 | nullui.disablepager() | |
1833 | revs = opts.get(b'rev') |
|
1856 | revs = opts.get(b'rev') | |
1834 | if not revs: |
|
1857 | if not revs: | |
@@ -1855,7 +1878,6 b' def perftemplating(ui, repo, testedtempl' | |||||
1855 |
|
1878 | |||
1856 |
|
1879 | |||
1857 | def _displaystats(ui, opts, entries, data): |
|
1880 | def _displaystats(ui, opts, entries, data): | |
1858 | pass |
|
|||
1859 | # use a second formatter because the data are quite different, not sure |
|
1881 | # use a second formatter because the data are quite different, not sure | |
1860 | # how it flies with the templater. |
|
1882 | # how it flies with the templater. | |
1861 | fm = ui.formatter(b'perf-stats', opts) |
|
1883 | fm = ui.formatter(b'perf-stats', opts) | |
@@ -2025,8 +2047,8 b' def perfhelpermergecopies(ui, repo, revs' | |||||
2025 | data['p1.time'] = end - begin |
|
2047 | data['p1.time'] = end - begin | |
2026 | begin = util.timer() |
|
2048 | begin = util.timer() | |
2027 | p2renames = copies.pathcopies(b, p2) |
|
2049 | p2renames = copies.pathcopies(b, p2) | |
|
2050 | end = util.timer() | |||
2028 | data['p2.time'] = end - begin |
|
2051 | data['p2.time'] = end - begin | |
2029 | end = util.timer() |
|
|||
2030 | data['p1.renamedfiles'] = len(p1renames) |
|
2052 | data['p1.renamedfiles'] = len(p1renames) | |
2031 | data['p2.renamedfiles'] = len(p2renames) |
|
2053 | data['p2.renamedfiles'] = len(p2renames) | |
2032 |
|
2054 | |||
@@ -2198,9 +2220,6 b' def perfhelperpathcopies(ui, repo, revs=' | |||||
2198 |
|
2220 | |||
2199 | fm.end() |
|
2221 | fm.end() | |
2200 | if dostats: |
|
2222 | if dostats: | |
2201 | # use a second formatter because the data are quite different, not sure |
|
|||
2202 | # how it flies with the templater. |
|
|||
2203 | fm = ui.formatter(b'perf', opts) |
|
|||
2204 | entries = [ |
|
2223 | entries = [ | |
2205 | ('nbrevs', 'number of revision covered'), |
|
2224 | ('nbrevs', 'number of revision covered'), | |
2206 | ('nbmissingfiles', 'number of missing files at head'), |
|
2225 | ('nbmissingfiles', 'number of missing files at head'), | |
@@ -2576,25 +2595,38 b' def perfrevlogindex(ui, repo, file_=None' | |||||
2576 | index[rev] |
|
2595 | index[rev] | |
2577 |
|
2596 | |||
2578 | def resolvenode(node): |
|
2597 | def resolvenode(node): | |
2579 |
|
|
2598 | index = revlogio.parseindex(data, inline)[0] | |
2580 | # This only works for the C code. |
|
2599 | rev = getattr(index, 'rev', None) | |
2581 |
if |
|
2600 | if rev is None: | |
2582 |
|
|
2601 | nodemap = getattr( | |
|
2602 | revlogio.parseindex(data, inline)[0], 'nodemap', None | |||
|
2603 | ) | |||
|
2604 | # This only works for the C code. | |||
|
2605 | if nodemap is None: | |||
|
2606 | return | |||
|
2607 | rev = nodemap.__getitem__ | |||
2583 |
|
2608 | |||
2584 | try: |
|
2609 | try: | |
2585 |
|
|
2610 | rev(node) | |
2586 | except error.RevlogError: |
|
2611 | except error.RevlogError: | |
2587 | pass |
|
2612 | pass | |
2588 |
|
2613 | |||
2589 | def resolvenodes(nodes, count=1): |
|
2614 | def resolvenodes(nodes, count=1): | |
2590 |
|
|
2615 | index = revlogio.parseindex(data, inline)[0] | |
2591 | if nodemap is None: |
|
2616 | rev = getattr(index, 'rev', None) | |
2592 | return |
|
2617 | if rev is None: | |
|
2618 | nodemap = getattr( | |||
|
2619 | revlogio.parseindex(data, inline)[0], 'nodemap', None | |||
|
2620 | ) | |||
|
2621 | # This only works for the C code. | |||
|
2622 | if nodemap is None: | |||
|
2623 | return | |||
|
2624 | rev = nodemap.__getitem__ | |||
2593 |
|
2625 | |||
2594 | for i in range(count): |
|
2626 | for i in range(count): | |
2595 | for node in nodes: |
|
2627 | for node in nodes: | |
2596 | try: |
|
2628 | try: | |
2597 |
|
|
2629 | rev(node) | |
2598 | except error.RevlogError: |
|
2630 | except error.RevlogError: | |
2599 | pass |
|
2631 | pass | |
2600 |
|
2632 |
@@ -43,13 +43,18 b' Actions Blocking Release' | |||||
43 | * Support modifying compression parameters mid operation when supported by |
|
43 | * Support modifying compression parameters mid operation when supported by | |
44 | zstd API. |
|
44 | zstd API. | |
45 | * Expose ``ZSTD_CLEVEL_DEFAULT`` constant. |
|
45 | * Expose ``ZSTD_CLEVEL_DEFAULT`` constant. | |
|
46 | * Expose ``ZSTD_SRCSIZEHINT_{MIN,MAX}`` constants. | |||
46 | * Support ``ZSTD_p_forceAttachDict`` compression parameter. |
|
47 | * Support ``ZSTD_p_forceAttachDict`` compression parameter. | |
47 |
* Support ``ZSTD_ |
|
48 | * Support ``ZSTD_dictForceLoad`` dictionary compression parameter. | |
|
49 | * Support ``ZSTD_c_targetCBlockSize`` compression parameter. | |||
|
50 | * Support ``ZSTD_c_literalCompressionMode`` compression parameter. | |||
|
51 | * Support ``ZSTD_c_srcSizeHint`` compression parameter. | |||
48 | * Use ``ZSTD_CCtx_getParameter()``/``ZSTD_CCtxParam_getParameter()`` for retrieving |
|
52 | * Use ``ZSTD_CCtx_getParameter()``/``ZSTD_CCtxParam_getParameter()`` for retrieving | |
49 | compression parameters. |
|
53 | compression parameters. | |
50 | * Consider exposing ``ZSTDMT_toFlushNow()``. |
|
54 | * Consider exposing ``ZSTDMT_toFlushNow()``. | |
51 | * Expose ``ZDICT_trainFromBuffer_fastCover()``, |
|
55 | * Expose ``ZDICT_trainFromBuffer_fastCover()``, | |
52 | ``ZDICT_optimizeTrainFromBuffer_fastCover``. |
|
56 | ``ZDICT_optimizeTrainFromBuffer_fastCover``. | |
|
57 | * Expose ``ZSTD_Sequence`` struct and related ``ZSTD_getSequences()`` API. | |||
53 | * Expose and enforce ``ZSTD_minCLevel()`` for minimum compression level. |
|
58 | * Expose and enforce ``ZSTD_minCLevel()`` for minimum compression level. | |
54 | * Consider a ``chunker()`` API for decompression. |
|
59 | * Consider a ``chunker()`` API for decompression. | |
55 | * Consider stats for ``chunker()`` API, including finding the last consumed |
|
60 | * Consider stats for ``chunker()`` API, including finding the last consumed | |
@@ -67,6 +72,20 b' Other Actions Not Blocking Release' | |||||
67 | * API for ensuring max memory ceiling isn't exceeded. |
|
72 | * API for ensuring max memory ceiling isn't exceeded. | |
68 | * Move off nose for testing. |
|
73 | * Move off nose for testing. | |
69 |
|
74 | |||
|
75 | 0.13.0 (released 2019-12-28) | |||
|
76 | ============================ | |||
|
77 | ||||
|
78 | Changes | |||
|
79 | ------- | |||
|
80 | ||||
|
81 | * ``pytest-xdist`` ``pytest`` extension is now installed so tests can be | |||
|
82 | run in parallel. | |||
|
83 | * CI now builds ``manylinux2010`` and ``manylinux2014`` binary wheels | |||
|
84 | instead of a mix of ``manylinux2010`` and ``manylinux1``. | |||
|
85 | * Official support for Python 3.8 has been added. | |||
|
86 | * Bundled zstandard library upgraded from 1.4.3 to 1.4.4. | |||
|
87 | * Python code has been reformatted with black. | |||
|
88 | ||||
70 | 0.12.0 (released 2019-09-15) |
|
89 | 0.12.0 (released 2019-09-15) | |
71 | ============================ |
|
90 | ============================ | |
72 |
|
91 |
@@ -20,7 +20,7 b' https://github.com/indygreg/python-zstan' | |||||
20 | Requirements |
|
20 | Requirements | |
21 | ============ |
|
21 | ============ | |
22 |
|
22 | |||
23 |
This extension is designed to run with Python 2.7, 3. |
|
23 | This extension is designed to run with Python 2.7, 3.5, 3.6, 3.7, and 3.8 | |
24 | on common platforms (Linux, Windows, and OS X). On PyPy (both PyPy2 and PyPy3) we support version 6.0.0 and above. |
|
24 | on common platforms (Linux, Windows, and OS X). On PyPy (both PyPy2 and PyPy3) we support version 6.0.0 and above. | |
25 | x86 and x86_64 are well-tested on Windows. Only x86_64 is well-tested on Linux and macOS. |
|
25 | x86 and x86_64 are well-tested on Windows. Only x86_64 is well-tested on Linux and macOS. | |
26 |
|
26 |
@@ -16,7 +16,7 b'' | |||||
16 | #include <zdict.h> |
|
16 | #include <zdict.h> | |
17 |
|
17 | |||
18 | /* Remember to change the string in zstandard/__init__ as well */ |
|
18 | /* Remember to change the string in zstandard/__init__ as well */ | |
19 |
#define PYTHON_ZSTANDARD_VERSION "0.1 |
|
19 | #define PYTHON_ZSTANDARD_VERSION "0.13.0" | |
20 |
|
20 | |||
21 | typedef enum { |
|
21 | typedef enum { | |
22 | compressorobj_flush_finish, |
|
22 | compressorobj_flush_finish, |
@@ -16,80 +16,82 b' import tempfile' | |||||
16 |
|
16 | |||
17 | HERE = os.path.abspath(os.path.dirname(__file__)) |
|
17 | HERE = os.path.abspath(os.path.dirname(__file__)) | |
18 |
|
18 | |||
19 | SOURCES = ['zstd/%s' % p for p in ( |
|
19 | SOURCES = [ | |
20 | 'common/debug.c', |
|
20 | "zstd/%s" % p | |
21 | 'common/entropy_common.c', |
|
21 | for p in ( | |
22 | 'common/error_private.c', |
|
22 | "common/debug.c", | |
23 | 'common/fse_decompress.c', |
|
23 | "common/entropy_common.c", | |
24 | 'common/pool.c', |
|
24 | "common/error_private.c", | |
25 | 'common/threading.c', |
|
25 | "common/fse_decompress.c", | |
26 |
|
|
26 | "common/pool.c", | |
27 |
|
|
27 | "common/threading.c", | |
28 | 'compress/fse_compress.c', |
|
28 | "common/xxhash.c", | |
29 | 'compress/hist.c', |
|
29 | "common/zstd_common.c", | |
30 |
|
|
30 | "compress/fse_compress.c", | |
31 |
|
|
31 | "compress/hist.c", | |
32 |
|
|
32 | "compress/huf_compress.c", | |
33 |
|
|
33 | "compress/zstd_compress.c", | |
34 |
|
|
34 | "compress/zstd_compress_literals.c", | |
35 |
|
|
35 | "compress/zstd_compress_sequences.c", | |
36 |
|
|
36 | "compress/zstd_double_fast.c", | |
37 |
|
|
37 | "compress/zstd_fast.c", | |
38 |
|
|
38 | "compress/zstd_lazy.c", | |
39 |
|
|
39 | "compress/zstd_ldm.c", | |
40 | 'decompress/huf_decompress.c', |
|
40 | "compress/zstd_opt.c", | |
41 |
|
|
41 | "compress/zstdmt_compress.c", | |
42 |
|
|
42 | "decompress/huf_decompress.c", | |
43 |
|
|
43 | "decompress/zstd_ddict.c", | |
44 | 'dictBuilder/cover.c', |
|
44 | "decompress/zstd_decompress.c", | |
45 | 'dictBuilder/fastcover.c', |
|
45 | "decompress/zstd_decompress_block.c", | |
46 |
|
|
46 | "dictBuilder/cover.c", | |
47 |
|
|
47 | "dictBuilder/fastcover.c", | |
48 | )] |
|
48 | "dictBuilder/divsufsort.c", | |
|
49 | "dictBuilder/zdict.c", | |||
|
50 | ) | |||
|
51 | ] | |||
49 |
|
52 | |||
50 | # Headers whose preprocessed output will be fed into cdef(). |
|
53 | # Headers whose preprocessed output will be fed into cdef(). | |
51 | HEADERS = [os.path.join(HERE, 'zstd', *p) for p in ( |
|
54 | HEADERS = [ | |
52 | ('zstd.h',), |
|
55 | os.path.join(HERE, "zstd", *p) for p in (("zstd.h",), ("dictBuilder", "zdict.h"),) | |
53 | ('dictBuilder', 'zdict.h'), |
|
56 | ] | |
54 | )] |
|
|||
55 |
|
57 | |||
56 | INCLUDE_DIRS = [os.path.join(HERE, d) for d in ( |
|
58 | INCLUDE_DIRS = [ | |
57 | 'zstd', |
|
59 | os.path.join(HERE, d) | |
58 | 'zstd/common', |
|
60 | for d in ( | |
59 | 'zstd/compress', |
|
61 | "zstd", | |
60 | 'zstd/decompress', |
|
62 | "zstd/common", | |
61 | 'zstd/dictBuilder', |
|
63 | "zstd/compress", | |
62 | )] |
|
64 | "zstd/decompress", | |
|
65 | "zstd/dictBuilder", | |||
|
66 | ) | |||
|
67 | ] | |||
63 |
|
68 | |||
64 | # cffi can't parse some of the primitives in zstd.h. So we invoke the |
|
69 | # cffi can't parse some of the primitives in zstd.h. So we invoke the | |
65 | # preprocessor and feed its output into cffi. |
|
70 | # preprocessor and feed its output into cffi. | |
66 | compiler = distutils.ccompiler.new_compiler() |
|
71 | compiler = distutils.ccompiler.new_compiler() | |
67 |
|
72 | |||
68 | # Needed for MSVC. |
|
73 | # Needed for MSVC. | |
69 |
if hasattr(compiler, |
|
74 | if hasattr(compiler, "initialize"): | |
70 | compiler.initialize() |
|
75 | compiler.initialize() | |
71 |
|
76 | |||
72 | # Distutils doesn't set compiler.preprocessor, so invoke the preprocessor |
|
77 | # Distutils doesn't set compiler.preprocessor, so invoke the preprocessor | |
73 | # manually. |
|
78 | # manually. | |
74 |
if compiler.compiler_type == |
|
79 | if compiler.compiler_type == "unix": | |
75 |
args = list(compiler.executables[ |
|
80 | args = list(compiler.executables["compiler"]) | |
76 |
args.extend( |
|
81 | args.extend( | |
77 | '-E', |
|
82 | ["-E", "-DZSTD_STATIC_LINKING_ONLY", "-DZDICT_STATIC_LINKING_ONLY",] | |
78 | '-DZSTD_STATIC_LINKING_ONLY', |
|
83 | ) | |
79 | '-DZDICT_STATIC_LINKING_ONLY', |
|
84 | elif compiler.compiler_type == "msvc": | |
80 | ]) |
|
|||
81 | elif compiler.compiler_type == 'msvc': |
|
|||
82 | args = [compiler.cc] |
|
85 | args = [compiler.cc] | |
83 |
args.extend( |
|
86 | args.extend( | |
84 | '/EP', |
|
87 | ["/EP", "/DZSTD_STATIC_LINKING_ONLY", "/DZDICT_STATIC_LINKING_ONLY",] | |
85 | '/DZSTD_STATIC_LINKING_ONLY', |
|
88 | ) | |
86 | '/DZDICT_STATIC_LINKING_ONLY', |
|
|||
87 | ]) |
|
|||
88 | else: |
|
89 | else: | |
89 |
raise Exception( |
|
90 | raise Exception("unsupported compiler type: %s" % compiler.compiler_type) | |
|
91 | ||||
90 |
|
92 | |||
91 | def preprocess(path): |
|
93 | def preprocess(path): | |
92 |
with open(path, |
|
94 | with open(path, "rb") as fh: | |
93 | lines = [] |
|
95 | lines = [] | |
94 | it = iter(fh) |
|
96 | it = iter(fh) | |
95 |
|
97 | |||
@@ -104,32 +106,44 b' def preprocess(path):' | |||||
104 | # We define ZSTD_STATIC_LINKING_ONLY, which is redundant with the inline |
|
106 | # We define ZSTD_STATIC_LINKING_ONLY, which is redundant with the inline | |
105 | # #define in zstdmt_compress.h and results in a compiler warning. So drop |
|
107 | # #define in zstdmt_compress.h and results in a compiler warning. So drop | |
106 | # the inline #define. |
|
108 | # the inline #define. | |
107 |
if l.startswith( |
|
109 | if l.startswith( | |
108 | b'#include "zstd.h"', |
|
110 | ( | |
109 | b'#define ZSTD_STATIC_LINKING_ONLY')): |
|
111 | b"#include <stddef.h>", | |
|
112 | b'#include "zstd.h"', | |||
|
113 | b"#define ZSTD_STATIC_LINKING_ONLY", | |||
|
114 | ) | |||
|
115 | ): | |||
110 | continue |
|
116 | continue | |
111 |
|
117 | |||
|
118 | # The preprocessor environment on Windows doesn't define include | |||
|
119 | # paths, so the #include of limits.h fails. We work around this | |||
|
120 | # by removing that import and defining INT_MAX ourselves. This is | |||
|
121 | # a bit hacky. But it gets the job done. | |||
|
122 | # TODO make limits.h work on Windows so we ensure INT_MAX is | |||
|
123 | # correct. | |||
|
124 | if l.startswith(b"#include <limits.h>"): | |||
|
125 | l = b"#define INT_MAX 2147483647\n" | |||
|
126 | ||||
112 | # ZSTDLIB_API may not be defined if we dropped zstd.h. It isn't |
|
127 | # ZSTDLIB_API may not be defined if we dropped zstd.h. It isn't | |
113 | # important so just filter it out. |
|
128 | # important so just filter it out. | |
114 |
if l.startswith(b |
|
129 | if l.startswith(b"ZSTDLIB_API"): | |
115 |
l = l[len(b |
|
130 | l = l[len(b"ZSTDLIB_API ") :] | |
116 |
|
131 | |||
117 | lines.append(l) |
|
132 | lines.append(l) | |
118 |
|
133 | |||
119 |
fd, input_file = tempfile.mkstemp(suffix= |
|
134 | fd, input_file = tempfile.mkstemp(suffix=".h") | |
120 |
os.write(fd, b |
|
135 | os.write(fd, b"".join(lines)) | |
121 | os.close(fd) |
|
136 | os.close(fd) | |
122 |
|
137 | |||
123 | try: |
|
138 | try: | |
124 | env = dict(os.environ) |
|
139 | env = dict(os.environ) | |
125 |
if getattr(compiler, |
|
140 | if getattr(compiler, "_paths", None): | |
126 |
env[ |
|
141 | env["PATH"] = compiler._paths | |
127 | process = subprocess.Popen(args + [input_file], stdout=subprocess.PIPE, |
|
142 | process = subprocess.Popen(args + [input_file], stdout=subprocess.PIPE, env=env) | |
128 | env=env) |
|
|||
129 | output = process.communicate()[0] |
|
143 | output = process.communicate()[0] | |
130 | ret = process.poll() |
|
144 | ret = process.poll() | |
131 | if ret: |
|
145 | if ret: | |
132 |
raise Exception( |
|
146 | raise Exception("preprocessor exited with error") | |
133 |
|
147 | |||
134 | return output |
|
148 | return output | |
135 | finally: |
|
149 | finally: | |
@@ -141,16 +155,16 b' def normalize_output(output):' | |||||
141 | for line in output.splitlines(): |
|
155 | for line in output.splitlines(): | |
142 | # CFFI's parser doesn't like __attribute__ on UNIX compilers. |
|
156 | # CFFI's parser doesn't like __attribute__ on UNIX compilers. | |
143 | if line.startswith(b'__attribute__ ((visibility ("default"))) '): |
|
157 | if line.startswith(b'__attribute__ ((visibility ("default"))) '): | |
144 | line = line[len(b'__attribute__ ((visibility ("default"))) '):] |
|
158 | line = line[len(b'__attribute__ ((visibility ("default"))) ') :] | |
145 |
|
159 | |||
146 |
if line.startswith(b |
|
160 | if line.startswith(b"__attribute__((deprecated("): | |
147 | continue |
|
161 | continue | |
148 |
elif b |
|
162 | elif b"__declspec(deprecated(" in line: | |
149 | continue |
|
163 | continue | |
150 |
|
164 | |||
151 | lines.append(line) |
|
165 | lines.append(line) | |
152 |
|
166 | |||
153 |
return b |
|
167 | return b"\n".join(lines) | |
154 |
|
168 | |||
155 |
|
169 | |||
156 | ffi = cffi.FFI() |
|
170 | ffi = cffi.FFI() | |
@@ -159,18 +173,22 b' ffi = cffi.FFI()' | |||||
159 | # *_DISABLE_DEPRECATE_WARNINGS prevents the compiler from emitting a warning |
|
173 | # *_DISABLE_DEPRECATE_WARNINGS prevents the compiler from emitting a warning | |
160 | # when cffi uses the function. Since we statically link against zstd, even |
|
174 | # when cffi uses the function. Since we statically link against zstd, even | |
161 | # if we use the deprecated functions it shouldn't be a huge problem. |
|
175 | # if we use the deprecated functions it shouldn't be a huge problem. | |
162 |
ffi.set_source( |
|
176 | ffi.set_source( | |
|
177 | "_zstd_cffi", | |||
|
178 | """ | |||
163 |
|
|
179 | #define MIN(a,b) ((a)<(b) ? (a) : (b)) | |
164 |
|
|
180 | #define ZSTD_STATIC_LINKING_ONLY | |
165 |
|
|
181 | #include <zstd.h> | |
166 |
|
|
182 | #define ZDICT_STATIC_LINKING_ONLY | |
167 |
|
|
183 | #define ZDICT_DISABLE_DEPRECATE_WARNINGS | |
168 |
|
|
184 | #include <zdict.h> | |
169 | ''', sources=SOURCES, |
|
185 | """, | |
170 | include_dirs=INCLUDE_DIRS, |
|
186 | sources=SOURCES, | |
171 | extra_compile_args=['-DZSTD_MULTITHREAD']) |
|
187 | include_dirs=INCLUDE_DIRS, | |
|
188 | extra_compile_args=["-DZSTD_MULTITHREAD"], | |||
|
189 | ) | |||
172 |
|
190 | |||
173 |
DEFINE = re.compile(b |
|
191 | DEFINE = re.compile(b"^\\#define ([a-zA-Z0-9_]+) ") | |
174 |
|
192 | |||
175 | sources = [] |
|
193 | sources = [] | |
176 |
|
194 | |||
@@ -181,27 +199,27 b' for header in HEADERS:' | |||||
181 |
|
199 | |||
182 | # #define's are effectively erased as part of going through preprocessor. |
|
200 | # #define's are effectively erased as part of going through preprocessor. | |
183 | # So perform a manual pass to re-add those to the cdef source. |
|
201 | # So perform a manual pass to re-add those to the cdef source. | |
184 |
with open(header, |
|
202 | with open(header, "rb") as fh: | |
185 | for line in fh: |
|
203 | for line in fh: | |
186 | line = line.strip() |
|
204 | line = line.strip() | |
187 | m = DEFINE.match(line) |
|
205 | m = DEFINE.match(line) | |
188 | if not m: |
|
206 | if not m: | |
189 | continue |
|
207 | continue | |
190 |
|
208 | |||
191 |
if m.group(1) == b |
|
209 | if m.group(1) == b"ZSTD_STATIC_LINKING_ONLY": | |
192 | continue |
|
210 | continue | |
193 |
|
211 | |||
194 | # The parser doesn't like some constants with complex values. |
|
212 | # The parser doesn't like some constants with complex values. | |
195 |
if m.group(1) in (b |
|
213 | if m.group(1) in (b"ZSTD_LIB_VERSION", b"ZSTD_VERSION_STRING"): | |
196 | continue |
|
214 | continue | |
197 |
|
215 | |||
198 | # The ... is magic syntax by the cdef parser to resolve the |
|
216 | # The ... is magic syntax by the cdef parser to resolve the | |
199 | # value at compile time. |
|
217 | # value at compile time. | |
200 |
sources.append(m.group(0) + b |
|
218 | sources.append(m.group(0) + b" ...") | |
201 |
|
219 | |||
202 |
cdeflines = b |
|
220 | cdeflines = b"\n".join(sources).splitlines() | |
203 | cdeflines = [l for l in cdeflines if l.strip()] |
|
221 | cdeflines = [l for l in cdeflines if l.strip()] | |
204 |
ffi.cdef(b |
|
222 | ffi.cdef(b"\n".join(cdeflines).decode("latin1")) | |
205 |
|
223 | |||
206 |
if __name__ == |
|
224 | if __name__ == "__main__": | |
207 | ffi.compile() |
|
225 | ffi.compile() |
@@ -16,7 +16,7 b' from setuptools import setup' | |||||
16 | # (like memoryview). |
|
16 | # (like memoryview). | |
17 | # Need feature in 1.11 for ffi.gc() to declare size of objects so we avoid |
|
17 | # Need feature in 1.11 for ffi.gc() to declare size of objects so we avoid | |
18 | # garbage collection pitfalls. |
|
18 | # garbage collection pitfalls. | |
19 |
MINIMUM_CFFI_VERSION = |
|
19 | MINIMUM_CFFI_VERSION = "1.11" | |
20 |
|
20 | |||
21 | try: |
|
21 | try: | |
22 | import cffi |
|
22 | import cffi | |
@@ -26,9 +26,11 b' try:' | |||||
26 | # out the CFFI version here and reject CFFI if it is too old. |
|
26 | # out the CFFI version here and reject CFFI if it is too old. | |
27 | cffi_version = LooseVersion(cffi.__version__) |
|
27 | cffi_version = LooseVersion(cffi.__version__) | |
28 | if cffi_version < LooseVersion(MINIMUM_CFFI_VERSION): |
|
28 | if cffi_version < LooseVersion(MINIMUM_CFFI_VERSION): | |
29 | print('CFFI 1.11 or newer required (%s found); ' |
|
29 | print( | |
30 | 'not building CFFI backend' % cffi_version, |
|
30 | "CFFI 1.11 or newer required (%s found); " | |
31 | file=sys.stderr) |
|
31 | "not building CFFI backend" % cffi_version, | |
|
32 | file=sys.stderr, | |||
|
33 | ) | |||
32 | cffi = None |
|
34 | cffi = None | |
33 |
|
35 | |||
34 | except ImportError: |
|
36 | except ImportError: | |
@@ -40,73 +42,77 b' SUPPORT_LEGACY = False' | |||||
40 | SYSTEM_ZSTD = False |
|
42 | SYSTEM_ZSTD = False | |
41 | WARNINGS_AS_ERRORS = False |
|
43 | WARNINGS_AS_ERRORS = False | |
42 |
|
44 | |||
43 |
if os.environ.get( |
|
45 | if os.environ.get("ZSTD_WARNINGS_AS_ERRORS", ""): | |
44 | WARNINGS_AS_ERRORS = True |
|
46 | WARNINGS_AS_ERRORS = True | |
45 |
|
47 | |||
46 |
if |
|
48 | if "--legacy" in sys.argv: | |
47 | SUPPORT_LEGACY = True |
|
49 | SUPPORT_LEGACY = True | |
48 |
sys.argv.remove( |
|
50 | sys.argv.remove("--legacy") | |
49 |
|
51 | |||
50 |
if |
|
52 | if "--system-zstd" in sys.argv: | |
51 | SYSTEM_ZSTD = True |
|
53 | SYSTEM_ZSTD = True | |
52 |
sys.argv.remove( |
|
54 | sys.argv.remove("--system-zstd") | |
53 |
|
55 | |||
54 |
if |
|
56 | if "--warnings-as-errors" in sys.argv: | |
55 | WARNINGS_AS_ERRORS = True |
|
57 | WARNINGS_AS_ERRORS = True | |
56 |
sys.argv.remove( |
|
58 | sys.argv.remove("--warning-as-errors") | |
57 |
|
59 | |||
58 | # Code for obtaining the Extension instance is in its own module to |
|
60 | # Code for obtaining the Extension instance is in its own module to | |
59 | # facilitate reuse in other projects. |
|
61 | # facilitate reuse in other projects. | |
60 | extensions = [ |
|
62 | extensions = [ | |
61 |
setup_zstd.get_c_extension( |
|
63 | setup_zstd.get_c_extension( | |
62 | support_legacy=SUPPORT_LEGACY, |
|
64 | name="zstd", | |
63 | system_zstd=SYSTEM_ZSTD, |
|
65 | support_legacy=SUPPORT_LEGACY, | |
64 | warnings_as_errors=WARNINGS_AS_ERRORS), |
|
66 | system_zstd=SYSTEM_ZSTD, | |
|
67 | warnings_as_errors=WARNINGS_AS_ERRORS, | |||
|
68 | ), | |||
65 | ] |
|
69 | ] | |
66 |
|
70 | |||
67 | install_requires = [] |
|
71 | install_requires = [] | |
68 |
|
72 | |||
69 | if cffi: |
|
73 | if cffi: | |
70 | import make_cffi |
|
74 | import make_cffi | |
|
75 | ||||
71 | extensions.append(make_cffi.ffi.distutils_extension()) |
|
76 | extensions.append(make_cffi.ffi.distutils_extension()) | |
72 |
install_requires.append( |
|
77 | install_requires.append("cffi>=%s" % MINIMUM_CFFI_VERSION) | |
73 |
|
78 | |||
74 | version = None |
|
79 | version = None | |
75 |
|
80 | |||
76 |
with open( |
|
81 | with open("c-ext/python-zstandard.h", "r") as fh: | |
77 | for line in fh: |
|
82 | for line in fh: | |
78 |
if not line.startswith( |
|
83 | if not line.startswith("#define PYTHON_ZSTANDARD_VERSION"): | |
79 | continue |
|
84 | continue | |
80 |
|
85 | |||
81 | version = line.split()[2][1:-1] |
|
86 | version = line.split()[2][1:-1] | |
82 | break |
|
87 | break | |
83 |
|
88 | |||
84 | if not version: |
|
89 | if not version: | |
85 |
raise Exception( |
|
90 | raise Exception("could not resolve package version; " "this should never happen") | |
86 | 'this should never happen') |
|
|||
87 |
|
91 | |||
88 | setup( |
|
92 | setup( | |
89 |
name= |
|
93 | name="zstandard", | |
90 | version=version, |
|
94 | version=version, | |
91 |
description= |
|
95 | description="Zstandard bindings for Python", | |
92 |
long_description=open( |
|
96 | long_description=open("README.rst", "r").read(), | |
93 |
url= |
|
97 | url="https://github.com/indygreg/python-zstandard", | |
94 |
author= |
|
98 | author="Gregory Szorc", | |
95 |
author_email= |
|
99 | author_email="gregory.szorc@gmail.com", | |
96 |
license= |
|
100 | license="BSD", | |
97 | classifiers=[ |
|
101 | classifiers=[ | |
98 |
|
|
102 | "Development Status :: 4 - Beta", | |
99 |
|
|
103 | "Intended Audience :: Developers", | |
100 |
|
|
104 | "License :: OSI Approved :: BSD License", | |
101 |
|
|
105 | "Programming Language :: C", | |
102 |
|
|
106 | "Programming Language :: Python :: 2.7", | |
103 |
|
|
107 | "Programming Language :: Python :: 3.5", | |
104 |
|
|
108 | "Programming Language :: Python :: 3.6", | |
105 |
|
|
109 | "Programming Language :: Python :: 3.7", | |
|
110 | "Programming Language :: Python :: 3.8", | |||
106 | ], |
|
111 | ], | |
107 |
keywords= |
|
112 | keywords="zstandard zstd compression", | |
108 |
packages=[ |
|
113 | packages=["zstandard"], | |
109 | ext_modules=extensions, |
|
114 | ext_modules=extensions, | |
110 |
test_suite= |
|
115 | test_suite="tests", | |
111 | install_requires=install_requires, |
|
116 | install_requires=install_requires, | |
|
117 | tests_require=["hypothesis"], | |||
112 | ) |
|
118 | ) |
@@ -10,97 +10,110 b' import os' | |||||
10 | from distutils.extension import Extension |
|
10 | from distutils.extension import Extension | |
11 |
|
11 | |||
12 |
|
12 | |||
13 | zstd_sources = ['zstd/%s' % p for p in ( |
|
13 | zstd_sources = [ | |
14 | 'common/debug.c', |
|
14 | "zstd/%s" % p | |
15 | 'common/entropy_common.c', |
|
15 | for p in ( | |
16 | 'common/error_private.c', |
|
16 | "common/debug.c", | |
17 | 'common/fse_decompress.c', |
|
17 | "common/entropy_common.c", | |
18 | 'common/pool.c', |
|
18 | "common/error_private.c", | |
19 | 'common/threading.c', |
|
19 | "common/fse_decompress.c", | |
20 |
|
|
20 | "common/pool.c", | |
21 |
|
|
21 | "common/threading.c", | |
22 | 'compress/fse_compress.c', |
|
22 | "common/xxhash.c", | |
23 | 'compress/hist.c', |
|
23 | "common/zstd_common.c", | |
24 |
|
|
24 | "compress/fse_compress.c", | |
25 | 'compress/zstd_compress_literals.c', |
|
25 | "compress/hist.c", | |
26 |
|
|
26 | "compress/huf_compress.c", | |
27 |
|
|
27 | "compress/zstd_compress_literals.c", | |
28 |
|
|
28 | "compress/zstd_compress_sequences.c", | |
29 |
|
|
29 | "compress/zstd_compress.c", | |
30 |
|
|
30 | "compress/zstd_double_fast.c", | |
31 |
|
|
31 | "compress/zstd_fast.c", | |
32 |
|
|
32 | "compress/zstd_lazy.c", | |
33 |
|
|
33 | "compress/zstd_ldm.c", | |
34 | 'decompress/huf_decompress.c', |
|
34 | "compress/zstd_opt.c", | |
35 |
|
|
35 | "compress/zstdmt_compress.c", | |
36 |
|
|
36 | "decompress/huf_decompress.c", | |
37 |
|
|
37 | "decompress/zstd_ddict.c", | |
38 | 'dictBuilder/cover.c', |
|
38 | "decompress/zstd_decompress.c", | |
39 | 'dictBuilder/divsufsort.c', |
|
39 | "decompress/zstd_decompress_block.c", | |
40 |
|
|
40 | "dictBuilder/cover.c", | |
41 |
|
|
41 | "dictBuilder/divsufsort.c", | |
42 | )] |
|
42 | "dictBuilder/fastcover.c", | |
|
43 | "dictBuilder/zdict.c", | |||
|
44 | ) | |||
|
45 | ] | |||
43 |
|
46 | |||
44 |
zstd_sources_legacy = [ |
|
47 | zstd_sources_legacy = [ | |
45 | 'deprecated/zbuff_common.c', |
|
48 | "zstd/%s" % p | |
46 | 'deprecated/zbuff_compress.c', |
|
49 | for p in ( | |
47 |
|
|
50 | "deprecated/zbuff_common.c", | |
48 | 'legacy/zstd_v01.c', |
|
51 | "deprecated/zbuff_compress.c", | |
49 | 'legacy/zstd_v02.c', |
|
52 | "deprecated/zbuff_decompress.c", | |
50 |
|
|
53 | "legacy/zstd_v01.c", | |
51 |
|
|
54 | "legacy/zstd_v02.c", | |
52 |
|
|
55 | "legacy/zstd_v03.c", | |
53 |
|
|
56 | "legacy/zstd_v04.c", | |
54 |
|
|
57 | "legacy/zstd_v05.c", | |
55 | )] |
|
58 | "legacy/zstd_v06.c", | |
|
59 | "legacy/zstd_v07.c", | |||
|
60 | ) | |||
|
61 | ] | |||
56 |
|
62 | |||
57 | zstd_includes = [ |
|
63 | zstd_includes = [ | |
58 |
|
|
64 | "zstd", | |
59 |
|
|
65 | "zstd/common", | |
60 |
|
|
66 | "zstd/compress", | |
61 |
|
|
67 | "zstd/decompress", | |
62 |
|
|
68 | "zstd/dictBuilder", | |
63 | ] |
|
69 | ] | |
64 |
|
70 | |||
65 | zstd_includes_legacy = [ |
|
71 | zstd_includes_legacy = [ | |
66 |
|
|
72 | "zstd/deprecated", | |
67 |
|
|
73 | "zstd/legacy", | |
68 | ] |
|
74 | ] | |
69 |
|
75 | |||
70 | ext_includes = [ |
|
76 | ext_includes = [ | |
71 |
|
|
77 | "c-ext", | |
72 |
|
|
78 | "zstd/common", | |
73 | ] |
|
79 | ] | |
74 |
|
80 | |||
75 | ext_sources = [ |
|
81 | ext_sources = [ | |
76 |
|
|
82 | "zstd/common/error_private.c", | |
77 |
|
|
83 | "zstd/common/pool.c", | |
78 | 'zstd.c', |
|
84 | "zstd/common/threading.c", | |
79 | 'c-ext/bufferutil.c', |
|
85 | "zstd/common/zstd_common.c", | |
80 | 'c-ext/compressiondict.c', |
|
86 | "zstd.c", | |
81 | 'c-ext/compressobj.c', |
|
87 | "c-ext/bufferutil.c", | |
82 |
|
|
88 | "c-ext/compressiondict.c", | |
83 |
|
|
89 | "c-ext/compressobj.c", | |
84 |
|
|
90 | "c-ext/compressor.c", | |
85 |
|
|
91 | "c-ext/compressoriterator.c", | |
86 |
|
|
92 | "c-ext/compressionchunker.c", | |
87 |
|
|
93 | "c-ext/compressionparams.c", | |
88 |
|
|
94 | "c-ext/compressionreader.c", | |
89 |
|
|
95 | "c-ext/compressionwriter.c", | |
90 |
|
|
96 | "c-ext/constants.c", | |
91 |
|
|
97 | "c-ext/decompressobj.c", | |
92 |
|
|
98 | "c-ext/decompressor.c", | |
93 |
|
|
99 | "c-ext/decompressoriterator.c", | |
94 | 'c-ext/frameparams.c', |
|
100 | "c-ext/decompressionreader.c", | |
|
101 | "c-ext/decompressionwriter.c", | |||
|
102 | "c-ext/frameparams.c", | |||
95 | ] |
|
103 | ] | |
96 |
|
104 | |||
97 | zstd_depends = [ |
|
105 | zstd_depends = [ | |
98 |
|
|
106 | "c-ext/python-zstandard.h", | |
99 | ] |
|
107 | ] | |
100 |
|
108 | |||
101 |
|
109 | |||
102 | def get_c_extension(support_legacy=False, system_zstd=False, name='zstd', |
|
110 | def get_c_extension( | |
103 | warnings_as_errors=False, root=None): |
|
111 | support_legacy=False, | |
|
112 | system_zstd=False, | |||
|
113 | name="zstd", | |||
|
114 | warnings_as_errors=False, | |||
|
115 | root=None, | |||
|
116 | ): | |||
104 | """Obtain a distutils.extension.Extension for the C extension. |
|
117 | """Obtain a distutils.extension.Extension for the C extension. | |
105 |
|
118 | |||
106 | ``support_legacy`` controls whether to compile in legacy zstd format support. |
|
119 | ``support_legacy`` controls whether to compile in legacy zstd format support. | |
@@ -125,17 +138,16 b' def get_c_extension(support_legacy=False' | |||||
125 | if not system_zstd: |
|
138 | if not system_zstd: | |
126 | sources.update([os.path.join(actual_root, p) for p in zstd_sources]) |
|
139 | sources.update([os.path.join(actual_root, p) for p in zstd_sources]) | |
127 | if support_legacy: |
|
140 | if support_legacy: | |
128 | sources.update([os.path.join(actual_root, p) |
|
141 | sources.update([os.path.join(actual_root, p) for p in zstd_sources_legacy]) | |
129 | for p in zstd_sources_legacy]) |
|
|||
130 | sources = list(sources) |
|
142 | sources = list(sources) | |
131 |
|
143 | |||
132 | include_dirs = set([os.path.join(actual_root, d) for d in ext_includes]) |
|
144 | include_dirs = set([os.path.join(actual_root, d) for d in ext_includes]) | |
133 | if not system_zstd: |
|
145 | if not system_zstd: | |
134 | include_dirs.update([os.path.join(actual_root, d) |
|
146 | include_dirs.update([os.path.join(actual_root, d) for d in zstd_includes]) | |
135 | for d in zstd_includes]) |
|
|||
136 | if support_legacy: |
|
147 | if support_legacy: | |
137 |
include_dirs.update( |
|
148 | include_dirs.update( | |
138 |
|
|
149 | [os.path.join(actual_root, d) for d in zstd_includes_legacy] | |
|
150 | ) | |||
139 | include_dirs = list(include_dirs) |
|
151 | include_dirs = list(include_dirs) | |
140 |
|
152 | |||
141 | depends = [os.path.join(actual_root, p) for p in zstd_depends] |
|
153 | depends = [os.path.join(actual_root, p) for p in zstd_depends] | |
@@ -143,41 +155,40 b' def get_c_extension(support_legacy=False' | |||||
143 | compiler = distutils.ccompiler.new_compiler() |
|
155 | compiler = distutils.ccompiler.new_compiler() | |
144 |
|
156 | |||
145 | # Needed for MSVC. |
|
157 | # Needed for MSVC. | |
146 |
if hasattr(compiler, |
|
158 | if hasattr(compiler, "initialize"): | |
147 | compiler.initialize() |
|
159 | compiler.initialize() | |
148 |
|
160 | |||
149 |
if compiler.compiler_type == |
|
161 | if compiler.compiler_type == "unix": | |
150 |
compiler_type = |
|
162 | compiler_type = "unix" | |
151 |
elif compiler.compiler_type == |
|
163 | elif compiler.compiler_type == "msvc": | |
152 |
compiler_type = |
|
164 | compiler_type = "msvc" | |
153 |
elif compiler.compiler_type == |
|
165 | elif compiler.compiler_type == "mingw32": | |
154 |
compiler_type = |
|
166 | compiler_type = "mingw32" | |
155 | else: |
|
167 | else: | |
156 |
raise Exception( |
|
168 | raise Exception("unhandled compiler type: %s" % compiler.compiler_type) | |
157 | compiler.compiler_type) |
|
|||
158 |
|
169 | |||
159 |
extra_args = [ |
|
170 | extra_args = ["-DZSTD_MULTITHREAD"] | |
160 |
|
171 | |||
161 | if not system_zstd: |
|
172 | if not system_zstd: | |
162 |
extra_args.append( |
|
173 | extra_args.append("-DZSTDLIB_VISIBILITY=") | |
163 |
extra_args.append( |
|
174 | extra_args.append("-DZDICTLIB_VISIBILITY=") | |
164 |
extra_args.append( |
|
175 | extra_args.append("-DZSTDERRORLIB_VISIBILITY=") | |
165 |
|
176 | |||
166 |
if compiler_type == |
|
177 | if compiler_type == "unix": | |
167 |
extra_args.append( |
|
178 | extra_args.append("-fvisibility=hidden") | |
168 |
|
179 | |||
169 | if not system_zstd and support_legacy: |
|
180 | if not system_zstd and support_legacy: | |
170 |
extra_args.append( |
|
181 | extra_args.append("-DZSTD_LEGACY_SUPPORT=1") | |
171 |
|
182 | |||
172 | if warnings_as_errors: |
|
183 | if warnings_as_errors: | |
173 |
if compiler_type in ( |
|
184 | if compiler_type in ("unix", "mingw32"): | |
174 |
extra_args.append( |
|
185 | extra_args.append("-Werror") | |
175 |
elif compiler_type == |
|
186 | elif compiler_type == "msvc": | |
176 |
extra_args.append( |
|
187 | extra_args.append("/WX") | |
177 | else: |
|
188 | else: | |
178 | assert False |
|
189 | assert False | |
179 |
|
190 | |||
180 |
libraries = [ |
|
191 | libraries = ["zstd"] if system_zstd else [] | |
181 |
|
192 | |||
182 | # Python 3.7 doesn't like absolute paths. So normalize to relative. |
|
193 | # Python 3.7 doesn't like absolute paths. So normalize to relative. | |
183 | sources = [os.path.relpath(p, root) for p in sources] |
|
194 | sources = [os.path.relpath(p, root) for p in sources] | |
@@ -185,8 +196,11 b' def get_c_extension(support_legacy=False' | |||||
185 | depends = [os.path.relpath(p, root) for p in depends] |
|
196 | depends = [os.path.relpath(p, root) for p in depends] | |
186 |
|
197 | |||
187 | # TODO compile with optimizations. |
|
198 | # TODO compile with optimizations. | |
188 |
return Extension( |
|
199 | return Extension( | |
189 | include_dirs=include_dirs, |
|
200 | name, | |
190 | depends=depends, |
|
201 | sources, | |
191 | extra_compile_args=extra_args, |
|
202 | include_dirs=include_dirs, | |
192 | libraries=libraries) |
|
203 | depends=depends, | |
|
204 | extra_compile_args=extra_args, | |||
|
205 | libraries=libraries, | |||
|
206 | ) |
@@ -3,6 +3,7 b' import inspect' | |||||
3 | import io |
|
3 | import io | |
4 | import os |
|
4 | import os | |
5 | import types |
|
5 | import types | |
|
6 | import unittest | |||
6 |
|
7 | |||
7 | try: |
|
8 | try: | |
8 | import hypothesis |
|
9 | import hypothesis | |
@@ -10,39 +11,46 b' except ImportError:' | |||||
10 | hypothesis = None |
|
11 | hypothesis = None | |
11 |
|
12 | |||
12 |
|
13 | |||
|
14 | class TestCase(unittest.TestCase): | |||
|
15 | if not getattr(unittest.TestCase, "assertRaisesRegex", False): | |||
|
16 | assertRaisesRegex = unittest.TestCase.assertRaisesRegexp | |||
|
17 | ||||
|
18 | ||||
13 | def make_cffi(cls): |
|
19 | def make_cffi(cls): | |
14 | """Decorator to add CFFI versions of each test method.""" |
|
20 | """Decorator to add CFFI versions of each test method.""" | |
15 |
|
21 | |||
16 | # The module containing this class definition should |
|
22 | # The module containing this class definition should | |
17 | # `import zstandard as zstd`. Otherwise things may blow up. |
|
23 | # `import zstandard as zstd`. Otherwise things may blow up. | |
18 | mod = inspect.getmodule(cls) |
|
24 | mod = inspect.getmodule(cls) | |
19 |
if not hasattr(mod, |
|
25 | if not hasattr(mod, "zstd"): | |
20 | raise Exception('test module does not contain "zstd" symbol') |
|
26 | raise Exception('test module does not contain "zstd" symbol') | |
21 |
|
27 | |||
22 |
if not hasattr(mod.zstd, |
|
28 | if not hasattr(mod.zstd, "backend"): | |
23 | raise Exception('zstd symbol does not have "backend" attribute; did ' |
|
29 | raise Exception( | |
24 | 'you `import zstandard as zstd`?') |
|
30 | 'zstd symbol does not have "backend" attribute; did ' | |
|
31 | "you `import zstandard as zstd`?" | |||
|
32 | ) | |||
25 |
|
33 | |||
26 | # If `import zstandard` already chose the cffi backend, there is nothing |
|
34 | # If `import zstandard` already chose the cffi backend, there is nothing | |
27 | # for us to do: we only add the cffi variation if the default backend |
|
35 | # for us to do: we only add the cffi variation if the default backend | |
28 | # is the C extension. |
|
36 | # is the C extension. | |
29 |
if mod.zstd.backend == |
|
37 | if mod.zstd.backend == "cffi": | |
30 | return cls |
|
38 | return cls | |
31 |
|
39 | |||
32 | old_env = dict(os.environ) |
|
40 | old_env = dict(os.environ) | |
33 |
os.environ[ |
|
41 | os.environ["PYTHON_ZSTANDARD_IMPORT_POLICY"] = "cffi" | |
34 | try: |
|
42 | try: | |
35 | try: |
|
43 | try: | |
36 |
mod_info = imp.find_module( |
|
44 | mod_info = imp.find_module("zstandard") | |
37 |
mod = imp.load_module( |
|
45 | mod = imp.load_module("zstandard_cffi", *mod_info) | |
38 | except ImportError: |
|
46 | except ImportError: | |
39 | return cls |
|
47 | return cls | |
40 | finally: |
|
48 | finally: | |
41 | os.environ.clear() |
|
49 | os.environ.clear() | |
42 | os.environ.update(old_env) |
|
50 | os.environ.update(old_env) | |
43 |
|
51 | |||
44 |
if mod.backend != |
|
52 | if mod.backend != "cffi": | |
45 |
raise Exception( |
|
53 | raise Exception("got the zstandard %s backend instead of cffi" % mod.backend) | |
46 |
|
54 | |||
47 | # If CFFI version is available, dynamically construct test methods |
|
55 | # If CFFI version is available, dynamically construct test methods | |
48 | # that use it. |
|
56 | # that use it. | |
@@ -52,27 +60,31 b' def make_cffi(cls):' | |||||
52 | if not inspect.ismethod(fn) and not inspect.isfunction(fn): |
|
60 | if not inspect.ismethod(fn) and not inspect.isfunction(fn): | |
53 | continue |
|
61 | continue | |
54 |
|
62 | |||
55 |
if not fn.__name__.startswith( |
|
63 | if not fn.__name__.startswith("test_"): | |
56 | continue |
|
64 | continue | |
57 |
|
65 | |||
58 |
name = |
|
66 | name = "%s_cffi" % fn.__name__ | |
59 |
|
67 | |||
60 | # Replace the "zstd" symbol with the CFFI module instance. Then copy |
|
68 | # Replace the "zstd" symbol with the CFFI module instance. Then copy | |
61 | # the function object and install it in a new attribute. |
|
69 | # the function object and install it in a new attribute. | |
62 | if isinstance(fn, types.FunctionType): |
|
70 | if isinstance(fn, types.FunctionType): | |
63 | globs = dict(fn.__globals__) |
|
71 | globs = dict(fn.__globals__) | |
64 |
globs[ |
|
72 | globs["zstd"] = mod | |
65 |
new_fn = types.FunctionType( |
|
73 | new_fn = types.FunctionType( | |
66 |
|
|
74 | fn.__code__, globs, name, fn.__defaults__, fn.__closure__ | |
|
75 | ) | |||
67 | new_method = new_fn |
|
76 | new_method = new_fn | |
68 | else: |
|
77 | else: | |
69 | globs = dict(fn.__func__.func_globals) |
|
78 | globs = dict(fn.__func__.func_globals) | |
70 |
globs[ |
|
79 | globs["zstd"] = mod | |
71 |
new_fn = types.FunctionType( |
|
80 | new_fn = types.FunctionType( | |
72 |
|
|
81 | fn.__func__.func_code, | |
73 | fn.__func__.func_closure) |
|
82 | globs, | |
74 | new_method = types.UnboundMethodType(new_fn, fn.im_self, |
|
83 | name, | |
75 | fn.im_class) |
|
84 | fn.__func__.func_defaults, | |
|
85 | fn.__func__.func_closure, | |||
|
86 | ) | |||
|
87 | new_method = types.UnboundMethodType(new_fn, fn.im_self, fn.im_class) | |||
76 |
|
88 | |||
77 | setattr(cls, name, new_method) |
|
89 | setattr(cls, name, new_method) | |
78 |
|
90 | |||
@@ -84,6 +96,7 b' class NonClosingBytesIO(io.BytesIO):' | |||||
84 |
|
96 | |||
85 | This allows us to access written data after close(). |
|
97 | This allows us to access written data after close(). | |
86 | """ |
|
98 | """ | |
|
99 | ||||
87 | def __init__(self, *args, **kwargs): |
|
100 | def __init__(self, *args, **kwargs): | |
88 | super(NonClosingBytesIO, self).__init__(*args, **kwargs) |
|
101 | super(NonClosingBytesIO, self).__init__(*args, **kwargs) | |
89 | self._saved_buffer = None |
|
102 | self._saved_buffer = None | |
@@ -135,7 +148,7 b' def random_input_data():' | |||||
135 | dirs[:] = list(sorted(dirs)) |
|
148 | dirs[:] = list(sorted(dirs)) | |
136 | for f in sorted(files): |
|
149 | for f in sorted(files): | |
137 | try: |
|
150 | try: | |
138 |
with open(os.path.join(root, f), |
|
151 | with open(os.path.join(root, f), "rb") as fh: | |
139 | data = fh.read() |
|
152 | data = fh.read() | |
140 | if data: |
|
153 | if data: | |
141 | _source_files.append(data) |
|
154 | _source_files.append(data) | |
@@ -154,11 +167,11 b' def random_input_data():' | |||||
154 |
|
167 | |||
155 | def generate_samples(): |
|
168 | def generate_samples(): | |
156 | inputs = [ |
|
169 | inputs = [ | |
157 |
b |
|
170 | b"foo", | |
158 |
b |
|
171 | b"bar", | |
159 |
b |
|
172 | b"abcdef", | |
160 |
b |
|
173 | b"sometext", | |
161 |
b |
|
174 | b"baz", | |
162 | ] |
|
175 | ] | |
163 |
|
176 | |||
164 | samples = [] |
|
177 | samples = [] | |
@@ -173,13 +186,12 b' def generate_samples():' | |||||
173 |
|
186 | |||
174 | if hypothesis: |
|
187 | if hypothesis: | |
175 | default_settings = hypothesis.settings(deadline=10000) |
|
188 | default_settings = hypothesis.settings(deadline=10000) | |
176 |
hypothesis.settings.register_profile( |
|
189 | hypothesis.settings.register_profile("default", default_settings) | |
177 |
|
190 | |||
178 | ci_settings = hypothesis.settings(deadline=20000, max_examples=1000) |
|
191 | ci_settings = hypothesis.settings(deadline=20000, max_examples=1000) | |
179 |
hypothesis.settings.register_profile( |
|
192 | hypothesis.settings.register_profile("ci", ci_settings) | |
180 |
|
193 | |||
181 | expensive_settings = hypothesis.settings(deadline=None, max_examples=10000) |
|
194 | expensive_settings = hypothesis.settings(deadline=None, max_examples=10000) | |
182 |
hypothesis.settings.register_profile( |
|
195 | hypothesis.settings.register_profile("expensive", expensive_settings) | |
183 |
|
196 | |||
184 | hypothesis.settings.load_profile( |
|
197 | hypothesis.settings.load_profile(os.environ.get("HYPOTHESIS_PROFILE", "default")) | |
185 | os.environ.get('HYPOTHESIS_PROFILE', 'default')) |
|
@@ -3,104 +3,114 b' import unittest' | |||||
3 |
|
3 | |||
4 | import zstandard as zstd |
|
4 | import zstandard as zstd | |
5 |
|
5 | |||
6 | ss = struct.Struct('=QQ') |
|
6 | from .common import TestCase | |
|
7 | ||||
|
8 | ss = struct.Struct("=QQ") | |||
7 |
|
9 | |||
8 |
|
10 | |||
9 |
class TestBufferWithSegments( |
|
11 | class TestBufferWithSegments(TestCase): | |
10 | def test_arguments(self): |
|
12 | def test_arguments(self): | |
11 |
if not hasattr(zstd, |
|
13 | if not hasattr(zstd, "BufferWithSegments"): | |
12 |
self.skipTest( |
|
14 | self.skipTest("BufferWithSegments not available") | |
13 |
|
15 | |||
14 | with self.assertRaises(TypeError): |
|
16 | with self.assertRaises(TypeError): | |
15 | zstd.BufferWithSegments() |
|
17 | zstd.BufferWithSegments() | |
16 |
|
18 | |||
17 | with self.assertRaises(TypeError): |
|
19 | with self.assertRaises(TypeError): | |
18 |
zstd.BufferWithSegments(b |
|
20 | zstd.BufferWithSegments(b"foo") | |
19 |
|
21 | |||
20 | # Segments data should be a multiple of 16. |
|
22 | # Segments data should be a multiple of 16. | |
21 | with self.assertRaisesRegexp(ValueError, 'segments array size is not a multiple of 16'): |
|
23 | with self.assertRaisesRegex( | |
22 | zstd.BufferWithSegments(b'foo', b'\x00\x00') |
|
24 | ValueError, "segments array size is not a multiple of 16" | |
|
25 | ): | |||
|
26 | zstd.BufferWithSegments(b"foo", b"\x00\x00") | |||
23 |
|
27 | |||
24 | def test_invalid_offset(self): |
|
28 | def test_invalid_offset(self): | |
25 |
if not hasattr(zstd, |
|
29 | if not hasattr(zstd, "BufferWithSegments"): | |
26 |
self.skipTest( |
|
30 | self.skipTest("BufferWithSegments not available") | |
27 |
|
31 | |||
28 | with self.assertRaisesRegexp(ValueError, 'offset within segments array references memory'): |
|
32 | with self.assertRaisesRegex( | |
29 | zstd.BufferWithSegments(b'foo', ss.pack(0, 4)) |
|
33 | ValueError, "offset within segments array references memory" | |
|
34 | ): | |||
|
35 | zstd.BufferWithSegments(b"foo", ss.pack(0, 4)) | |||
30 |
|
36 | |||
31 | def test_invalid_getitem(self): |
|
37 | def test_invalid_getitem(self): | |
32 |
if not hasattr(zstd, |
|
38 | if not hasattr(zstd, "BufferWithSegments"): | |
33 |
self.skipTest( |
|
39 | self.skipTest("BufferWithSegments not available") | |
34 |
|
40 | |||
35 |
b = zstd.BufferWithSegments(b |
|
41 | b = zstd.BufferWithSegments(b"foo", ss.pack(0, 3)) | |
36 |
|
42 | |||
37 |
with self.assertRaisesRegex |
|
43 | with self.assertRaisesRegex(IndexError, "offset must be non-negative"): | |
38 | test = b[-10] |
|
44 | test = b[-10] | |
39 |
|
45 | |||
40 |
with self.assertRaisesRegex |
|
46 | with self.assertRaisesRegex(IndexError, "offset must be less than 1"): | |
41 | test = b[1] |
|
47 | test = b[1] | |
42 |
|
48 | |||
43 |
with self.assertRaisesRegex |
|
49 | with self.assertRaisesRegex(IndexError, "offset must be less than 1"): | |
44 | test = b[2] |
|
50 | test = b[2] | |
45 |
|
51 | |||
46 | def test_single(self): |
|
52 | def test_single(self): | |
47 |
if not hasattr(zstd, |
|
53 | if not hasattr(zstd, "BufferWithSegments"): | |
48 |
self.skipTest( |
|
54 | self.skipTest("BufferWithSegments not available") | |
49 |
|
55 | |||
50 |
b = zstd.BufferWithSegments(b |
|
56 | b = zstd.BufferWithSegments(b"foo", ss.pack(0, 3)) | |
51 | self.assertEqual(len(b), 1) |
|
57 | self.assertEqual(len(b), 1) | |
52 | self.assertEqual(b.size, 3) |
|
58 | self.assertEqual(b.size, 3) | |
53 |
self.assertEqual(b.tobytes(), b |
|
59 | self.assertEqual(b.tobytes(), b"foo") | |
54 |
|
60 | |||
55 | self.assertEqual(len(b[0]), 3) |
|
61 | self.assertEqual(len(b[0]), 3) | |
56 | self.assertEqual(b[0].offset, 0) |
|
62 | self.assertEqual(b[0].offset, 0) | |
57 |
self.assertEqual(b[0].tobytes(), b |
|
63 | self.assertEqual(b[0].tobytes(), b"foo") | |
58 |
|
64 | |||
59 | def test_multiple(self): |
|
65 | def test_multiple(self): | |
60 |
if not hasattr(zstd, |
|
66 | if not hasattr(zstd, "BufferWithSegments"): | |
61 |
self.skipTest( |
|
67 | self.skipTest("BufferWithSegments not available") | |
62 |
|
68 | |||
63 |
b = zstd.BufferWithSegments( |
|
69 | b = zstd.BufferWithSegments( | |
64 | ss.pack(3, 4), |
|
70 | b"foofooxfooxy", b"".join([ss.pack(0, 3), ss.pack(3, 4), ss.pack(7, 5)]) | |
65 | ss.pack(7, 5)])) |
|
71 | ) | |
66 | self.assertEqual(len(b), 3) |
|
72 | self.assertEqual(len(b), 3) | |
67 | self.assertEqual(b.size, 12) |
|
73 | self.assertEqual(b.size, 12) | |
68 |
self.assertEqual(b.tobytes(), b |
|
74 | self.assertEqual(b.tobytes(), b"foofooxfooxy") | |
69 |
|
75 | |||
70 |
self.assertEqual(b[0].tobytes(), b |
|
76 | self.assertEqual(b[0].tobytes(), b"foo") | |
71 |
self.assertEqual(b[1].tobytes(), b |
|
77 | self.assertEqual(b[1].tobytes(), b"foox") | |
72 |
self.assertEqual(b[2].tobytes(), b |
|
78 | self.assertEqual(b[2].tobytes(), b"fooxy") | |
73 |
|
79 | |||
74 |
|
80 | |||
75 |
class TestBufferWithSegmentsCollection( |
|
81 | class TestBufferWithSegmentsCollection(TestCase): | |
76 | def test_empty_constructor(self): |
|
82 | def test_empty_constructor(self): | |
77 |
if not hasattr(zstd, |
|
83 | if not hasattr(zstd, "BufferWithSegmentsCollection"): | |
78 |
self.skipTest( |
|
84 | self.skipTest("BufferWithSegmentsCollection not available") | |
79 |
|
85 | |||
80 |
with self.assertRaisesRegex |
|
86 | with self.assertRaisesRegex(ValueError, "must pass at least 1 argument"): | |
81 | zstd.BufferWithSegmentsCollection() |
|
87 | zstd.BufferWithSegmentsCollection() | |
82 |
|
88 | |||
83 | def test_argument_validation(self): |
|
89 | def test_argument_validation(self): | |
84 |
if not hasattr(zstd, |
|
90 | if not hasattr(zstd, "BufferWithSegmentsCollection"): | |
85 |
self.skipTest( |
|
91 | self.skipTest("BufferWithSegmentsCollection not available") | |
86 |
|
92 | |||
87 |
with self.assertRaisesRegex |
|
93 | with self.assertRaisesRegex(TypeError, "arguments must be BufferWithSegments"): | |
88 | zstd.BufferWithSegmentsCollection(None) |
|
94 | zstd.BufferWithSegmentsCollection(None) | |
89 |
|
95 | |||
90 |
with self.assertRaisesRegex |
|
96 | with self.assertRaisesRegex(TypeError, "arguments must be BufferWithSegments"): | |
91 |
zstd.BufferWithSegmentsCollection( |
|
97 | zstd.BufferWithSegmentsCollection( | |
92 | None) |
|
98 | zstd.BufferWithSegments(b"foo", ss.pack(0, 3)), None | |
|
99 | ) | |||
93 |
|
100 | |||
94 | with self.assertRaisesRegexp(ValueError, 'ZstdBufferWithSegments cannot be empty'): |
|
101 | with self.assertRaisesRegex( | |
95 | zstd.BufferWithSegmentsCollection(zstd.BufferWithSegments(b'', b'')) |
|
102 | ValueError, "ZstdBufferWithSegments cannot be empty" | |
|
103 | ): | |||
|
104 | zstd.BufferWithSegmentsCollection(zstd.BufferWithSegments(b"", b"")) | |||
96 |
|
105 | |||
97 | def test_length(self): |
|
106 | def test_length(self): | |
98 |
if not hasattr(zstd, |
|
107 | if not hasattr(zstd, "BufferWithSegmentsCollection"): | |
99 |
self.skipTest( |
|
108 | self.skipTest("BufferWithSegmentsCollection not available") | |
100 |
|
109 | |||
101 |
b1 = zstd.BufferWithSegments(b |
|
110 | b1 = zstd.BufferWithSegments(b"foo", ss.pack(0, 3)) | |
102 |
b2 = zstd.BufferWithSegments( |
|
111 | b2 = zstd.BufferWithSegments( | |
103 | ss.pack(3, 3)])) |
|
112 | b"barbaz", b"".join([ss.pack(0, 3), ss.pack(3, 3)]) | |
|
113 | ) | |||
104 |
|
114 | |||
105 | c = zstd.BufferWithSegmentsCollection(b1) |
|
115 | c = zstd.BufferWithSegmentsCollection(b1) | |
106 | self.assertEqual(len(c), 1) |
|
116 | self.assertEqual(len(c), 1) | |
@@ -115,21 +125,22 b' class TestBufferWithSegmentsCollection(u' | |||||
115 | self.assertEqual(c.size(), 9) |
|
125 | self.assertEqual(c.size(), 9) | |
116 |
|
126 | |||
117 | def test_getitem(self): |
|
127 | def test_getitem(self): | |
118 |
if not hasattr(zstd, |
|
128 | if not hasattr(zstd, "BufferWithSegmentsCollection"): | |
119 |
self.skipTest( |
|
129 | self.skipTest("BufferWithSegmentsCollection not available") | |
120 |
|
130 | |||
121 |
b1 = zstd.BufferWithSegments(b |
|
131 | b1 = zstd.BufferWithSegments(b"foo", ss.pack(0, 3)) | |
122 |
b2 = zstd.BufferWithSegments( |
|
132 | b2 = zstd.BufferWithSegments( | |
123 | ss.pack(3, 3)])) |
|
133 | b"barbaz", b"".join([ss.pack(0, 3), ss.pack(3, 3)]) | |
|
134 | ) | |||
124 |
|
135 | |||
125 | c = zstd.BufferWithSegmentsCollection(b1, b2) |
|
136 | c = zstd.BufferWithSegmentsCollection(b1, b2) | |
126 |
|
137 | |||
127 |
with self.assertRaisesRegex |
|
138 | with self.assertRaisesRegex(IndexError, "offset must be less than 3"): | |
128 | c[3] |
|
139 | c[3] | |
129 |
|
140 | |||
130 |
with self.assertRaisesRegex |
|
141 | with self.assertRaisesRegex(IndexError, "offset must be less than 3"): | |
131 | c[4] |
|
142 | c[4] | |
132 |
|
143 | |||
133 |
self.assertEqual(c[0].tobytes(), b |
|
144 | self.assertEqual(c[0].tobytes(), b"foo") | |
134 |
self.assertEqual(c[1].tobytes(), b |
|
145 | self.assertEqual(c[1].tobytes(), b"bar") | |
135 |
self.assertEqual(c[2].tobytes(), b |
|
146 | self.assertEqual(c[2].tobytes(), b"baz") |
This diff has been collapsed as it changes many lines, (811 lines changed) Show them Hide them | |||||
@@ -13,6 +13,7 b' from .common import (' | |||||
13 | make_cffi, |
|
13 | make_cffi, | |
14 | NonClosingBytesIO, |
|
14 | NonClosingBytesIO, | |
15 | OpCountingBytesIO, |
|
15 | OpCountingBytesIO, | |
|
16 | TestCase, | |||
16 | ) |
|
17 | ) | |
17 |
|
18 | |||
18 |
|
19 | |||
@@ -23,14 +24,13 b' else:' | |||||
23 |
|
24 | |||
24 |
|
25 | |||
25 | def multithreaded_chunk_size(level, source_size=0): |
|
26 | def multithreaded_chunk_size(level, source_size=0): | |
26 | params = zstd.ZstdCompressionParameters.from_level(level, |
|
27 | params = zstd.ZstdCompressionParameters.from_level(level, source_size=source_size) | |
27 | source_size=source_size) |
|
|||
28 |
|
28 | |||
29 | return 1 << (params.window_log + 2) |
|
29 | return 1 << (params.window_log + 2) | |
30 |
|
30 | |||
31 |
|
31 | |||
32 | @make_cffi |
|
32 | @make_cffi | |
33 |
class TestCompressor( |
|
33 | class TestCompressor(TestCase): | |
34 | def test_level_bounds(self): |
|
34 | def test_level_bounds(self): | |
35 | with self.assertRaises(ValueError): |
|
35 | with self.assertRaises(ValueError): | |
36 | zstd.ZstdCompressor(level=23) |
|
36 | zstd.ZstdCompressor(level=23) | |
@@ -41,11 +41,11 b' class TestCompressor(unittest.TestCase):' | |||||
41 |
|
41 | |||
42 |
|
42 | |||
43 | @make_cffi |
|
43 | @make_cffi | |
44 |
class TestCompressor_compress( |
|
44 | class TestCompressor_compress(TestCase): | |
45 | def test_compress_empty(self): |
|
45 | def test_compress_empty(self): | |
46 | cctx = zstd.ZstdCompressor(level=1, write_content_size=False) |
|
46 | cctx = zstd.ZstdCompressor(level=1, write_content_size=False) | |
47 |
result = cctx.compress(b |
|
47 | result = cctx.compress(b"") | |
48 |
self.assertEqual(result, b |
|
48 | self.assertEqual(result, b"\x28\xb5\x2f\xfd\x00\x48\x01\x00\x00") | |
49 | params = zstd.get_frame_parameters(result) |
|
49 | params = zstd.get_frame_parameters(result) | |
50 | self.assertEqual(params.content_size, zstd.CONTENTSIZE_UNKNOWN) |
|
50 | self.assertEqual(params.content_size, zstd.CONTENTSIZE_UNKNOWN) | |
51 | self.assertEqual(params.window_size, 524288) |
|
51 | self.assertEqual(params.window_size, 524288) | |
@@ -53,21 +53,21 b' class TestCompressor_compress(unittest.T' | |||||
53 | self.assertFalse(params.has_checksum, 0) |
|
53 | self.assertFalse(params.has_checksum, 0) | |
54 |
|
54 | |||
55 | cctx = zstd.ZstdCompressor() |
|
55 | cctx = zstd.ZstdCompressor() | |
56 |
result = cctx.compress(b |
|
56 | result = cctx.compress(b"") | |
57 |
self.assertEqual(result, b |
|
57 | self.assertEqual(result, b"\x28\xb5\x2f\xfd\x20\x00\x01\x00\x00") | |
58 | params = zstd.get_frame_parameters(result) |
|
58 | params = zstd.get_frame_parameters(result) | |
59 | self.assertEqual(params.content_size, 0) |
|
59 | self.assertEqual(params.content_size, 0) | |
60 |
|
60 | |||
61 | def test_input_types(self): |
|
61 | def test_input_types(self): | |
62 | cctx = zstd.ZstdCompressor(level=1, write_content_size=False) |
|
62 | cctx = zstd.ZstdCompressor(level=1, write_content_size=False) | |
63 |
expected = b |
|
63 | expected = b"\x28\xb5\x2f\xfd\x00\x00\x19\x00\x00\x66\x6f\x6f" | |
64 |
|
64 | |||
65 | mutable_array = bytearray(3) |
|
65 | mutable_array = bytearray(3) | |
66 |
mutable_array[:] = b |
|
66 | mutable_array[:] = b"foo" | |
67 |
|
67 | |||
68 | sources = [ |
|
68 | sources = [ | |
69 |
memoryview(b |
|
69 | memoryview(b"foo"), | |
70 |
bytearray(b |
|
70 | bytearray(b"foo"), | |
71 | mutable_array, |
|
71 | mutable_array, | |
72 | ] |
|
72 | ] | |
73 |
|
73 | |||
@@ -77,43 +77,46 b' class TestCompressor_compress(unittest.T' | |||||
77 | def test_compress_large(self): |
|
77 | def test_compress_large(self): | |
78 | chunks = [] |
|
78 | chunks = [] | |
79 | for i in range(255): |
|
79 | for i in range(255): | |
80 |
chunks.append(struct.Struct( |
|
80 | chunks.append(struct.Struct(">B").pack(i) * 16384) | |
81 |
|
81 | |||
82 | cctx = zstd.ZstdCompressor(level=3, write_content_size=False) |
|
82 | cctx = zstd.ZstdCompressor(level=3, write_content_size=False) | |
83 |
result = cctx.compress(b |
|
83 | result = cctx.compress(b"".join(chunks)) | |
84 | self.assertEqual(len(result), 999) |
|
84 | self.assertEqual(len(result), 999) | |
85 |
self.assertEqual(result[0:4], b |
|
85 | self.assertEqual(result[0:4], b"\x28\xb5\x2f\xfd") | |
86 |
|
86 | |||
87 | # This matches the test for read_to_iter() below. |
|
87 | # This matches the test for read_to_iter() below. | |
88 | cctx = zstd.ZstdCompressor(level=1, write_content_size=False) |
|
88 | cctx = zstd.ZstdCompressor(level=1, write_content_size=False) | |
89 |
result = cctx.compress(b |
|
89 | result = cctx.compress(b"f" * zstd.COMPRESSION_RECOMMENDED_INPUT_SIZE + b"o") | |
90 | self.assertEqual(result, b'\x28\xb5\x2f\xfd\x00\x40\x54\x00\x00' |
|
90 | self.assertEqual( | |
91 | b'\x10\x66\x66\x01\x00\xfb\xff\x39\xc0' |
|
91 | result, | |
92 | b'\x02\x09\x00\x00\x6f') |
|
92 | b"\x28\xb5\x2f\xfd\x00\x40\x54\x00\x00" | |
|
93 | b"\x10\x66\x66\x01\x00\xfb\xff\x39\xc0" | |||
|
94 | b"\x02\x09\x00\x00\x6f", | |||
|
95 | ) | |||
93 |
|
96 | |||
94 | def test_negative_level(self): |
|
97 | def test_negative_level(self): | |
95 | cctx = zstd.ZstdCompressor(level=-4) |
|
98 | cctx = zstd.ZstdCompressor(level=-4) | |
96 |
result = cctx.compress(b |
|
99 | result = cctx.compress(b"foo" * 256) | |
97 |
|
100 | |||
98 | def test_no_magic(self): |
|
101 | def test_no_magic(self): | |
99 | params = zstd.ZstdCompressionParameters.from_level( |
|
102 | params = zstd.ZstdCompressionParameters.from_level(1, format=zstd.FORMAT_ZSTD1) | |
100 | 1, format=zstd.FORMAT_ZSTD1) |
|
|||
101 | cctx = zstd.ZstdCompressor(compression_params=params) |
|
103 | cctx = zstd.ZstdCompressor(compression_params=params) | |
102 |
magic = cctx.compress(b |
|
104 | magic = cctx.compress(b"foobar") | |
103 |
|
105 | |||
104 | params = zstd.ZstdCompressionParameters.from_level( |
|
106 | params = zstd.ZstdCompressionParameters.from_level( | |
105 |
1, format=zstd.FORMAT_ZSTD1_MAGICLESS |
|
107 | 1, format=zstd.FORMAT_ZSTD1_MAGICLESS | |
|
108 | ) | |||
106 | cctx = zstd.ZstdCompressor(compression_params=params) |
|
109 | cctx = zstd.ZstdCompressor(compression_params=params) | |
107 |
no_magic = cctx.compress(b |
|
110 | no_magic = cctx.compress(b"foobar") | |
108 |
|
111 | |||
109 |
self.assertEqual(magic[0:4], b |
|
112 | self.assertEqual(magic[0:4], b"\x28\xb5\x2f\xfd") | |
110 | self.assertEqual(magic[4:], no_magic) |
|
113 | self.assertEqual(magic[4:], no_magic) | |
111 |
|
114 | |||
112 | def test_write_checksum(self): |
|
115 | def test_write_checksum(self): | |
113 | cctx = zstd.ZstdCompressor(level=1) |
|
116 | cctx = zstd.ZstdCompressor(level=1) | |
114 |
no_checksum = cctx.compress(b |
|
117 | no_checksum = cctx.compress(b"foobar") | |
115 | cctx = zstd.ZstdCompressor(level=1, write_checksum=True) |
|
118 | cctx = zstd.ZstdCompressor(level=1, write_checksum=True) | |
116 |
with_checksum = cctx.compress(b |
|
119 | with_checksum = cctx.compress(b"foobar") | |
117 |
|
120 | |||
118 | self.assertEqual(len(with_checksum), len(no_checksum) + 4) |
|
121 | self.assertEqual(len(with_checksum), len(no_checksum) + 4) | |
119 |
|
122 | |||
@@ -125,9 +128,9 b' class TestCompressor_compress(unittest.T' | |||||
125 |
|
128 | |||
126 | def test_write_content_size(self): |
|
129 | def test_write_content_size(self): | |
127 | cctx = zstd.ZstdCompressor(level=1) |
|
130 | cctx = zstd.ZstdCompressor(level=1) | |
128 |
with_size = cctx.compress(b |
|
131 | with_size = cctx.compress(b"foobar" * 256) | |
129 | cctx = zstd.ZstdCompressor(level=1, write_content_size=False) |
|
132 | cctx = zstd.ZstdCompressor(level=1, write_content_size=False) | |
130 |
no_size = cctx.compress(b |
|
133 | no_size = cctx.compress(b"foobar" * 256) | |
131 |
|
134 | |||
132 | self.assertEqual(len(with_size), len(no_size) + 1) |
|
135 | self.assertEqual(len(with_size), len(no_size) + 1) | |
133 |
|
136 | |||
@@ -139,17 +142,17 b' class TestCompressor_compress(unittest.T' | |||||
139 | def test_no_dict_id(self): |
|
142 | def test_no_dict_id(self): | |
140 | samples = [] |
|
143 | samples = [] | |
141 | for i in range(128): |
|
144 | for i in range(128): | |
142 |
samples.append(b |
|
145 | samples.append(b"foo" * 64) | |
143 |
samples.append(b |
|
146 | samples.append(b"bar" * 64) | |
144 |
samples.append(b |
|
147 | samples.append(b"foobar" * 64) | |
145 |
|
148 | |||
146 | d = zstd.train_dictionary(1024, samples) |
|
149 | d = zstd.train_dictionary(1024, samples) | |
147 |
|
150 | |||
148 | cctx = zstd.ZstdCompressor(level=1, dict_data=d) |
|
151 | cctx = zstd.ZstdCompressor(level=1, dict_data=d) | |
149 |
with_dict_id = cctx.compress(b |
|
152 | with_dict_id = cctx.compress(b"foobarfoobar") | |
150 |
|
153 | |||
151 | cctx = zstd.ZstdCompressor(level=1, dict_data=d, write_dict_id=False) |
|
154 | cctx = zstd.ZstdCompressor(level=1, dict_data=d, write_dict_id=False) | |
152 |
no_dict_id = cctx.compress(b |
|
155 | no_dict_id = cctx.compress(b"foobarfoobar") | |
153 |
|
156 | |||
154 | self.assertEqual(len(with_dict_id), len(no_dict_id) + 4) |
|
157 | self.assertEqual(len(with_dict_id), len(no_dict_id) + 4) | |
155 |
|
158 | |||
@@ -161,23 +164,23 b' class TestCompressor_compress(unittest.T' | |||||
161 | def test_compress_dict_multiple(self): |
|
164 | def test_compress_dict_multiple(self): | |
162 | samples = [] |
|
165 | samples = [] | |
163 | for i in range(128): |
|
166 | for i in range(128): | |
164 |
samples.append(b |
|
167 | samples.append(b"foo" * 64) | |
165 |
samples.append(b |
|
168 | samples.append(b"bar" * 64) | |
166 |
samples.append(b |
|
169 | samples.append(b"foobar" * 64) | |
167 |
|
170 | |||
168 | d = zstd.train_dictionary(8192, samples) |
|
171 | d = zstd.train_dictionary(8192, samples) | |
169 |
|
172 | |||
170 | cctx = zstd.ZstdCompressor(level=1, dict_data=d) |
|
173 | cctx = zstd.ZstdCompressor(level=1, dict_data=d) | |
171 |
|
174 | |||
172 | for i in range(32): |
|
175 | for i in range(32): | |
173 |
cctx.compress(b |
|
176 | cctx.compress(b"foo bar foobar foo bar foobar") | |
174 |
|
177 | |||
175 | def test_dict_precompute(self): |
|
178 | def test_dict_precompute(self): | |
176 | samples = [] |
|
179 | samples = [] | |
177 | for i in range(128): |
|
180 | for i in range(128): | |
178 |
samples.append(b |
|
181 | samples.append(b"foo" * 64) | |
179 |
samples.append(b |
|
182 | samples.append(b"bar" * 64) | |
180 |
samples.append(b |
|
183 | samples.append(b"foobar" * 64) | |
181 |
|
184 | |||
182 | d = zstd.train_dictionary(8192, samples) |
|
185 | d = zstd.train_dictionary(8192, samples) | |
183 | d.precompute_compress(level=1) |
|
186 | d.precompute_compress(level=1) | |
@@ -185,11 +188,11 b' class TestCompressor_compress(unittest.T' | |||||
185 | cctx = zstd.ZstdCompressor(level=1, dict_data=d) |
|
188 | cctx = zstd.ZstdCompressor(level=1, dict_data=d) | |
186 |
|
189 | |||
187 | for i in range(32): |
|
190 | for i in range(32): | |
188 |
cctx.compress(b |
|
191 | cctx.compress(b"foo bar foobar foo bar foobar") | |
189 |
|
192 | |||
190 | def test_multithreaded(self): |
|
193 | def test_multithreaded(self): | |
191 | chunk_size = multithreaded_chunk_size(1) |
|
194 | chunk_size = multithreaded_chunk_size(1) | |
192 |
source = b |
|
195 | source = b"".join([b"x" * chunk_size, b"y" * chunk_size]) | |
193 |
|
196 | |||
194 | cctx = zstd.ZstdCompressor(level=1, threads=2) |
|
197 | cctx = zstd.ZstdCompressor(level=1, threads=2) | |
195 | compressed = cctx.compress(source) |
|
198 | compressed = cctx.compress(source) | |
@@ -205,73 +208,72 b' class TestCompressor_compress(unittest.T' | |||||
205 | def test_multithreaded_dict(self): |
|
208 | def test_multithreaded_dict(self): | |
206 | samples = [] |
|
209 | samples = [] | |
207 | for i in range(128): |
|
210 | for i in range(128): | |
208 |
samples.append(b |
|
211 | samples.append(b"foo" * 64) | |
209 |
samples.append(b |
|
212 | samples.append(b"bar" * 64) | |
210 |
samples.append(b |
|
213 | samples.append(b"foobar" * 64) | |
211 |
|
214 | |||
212 | d = zstd.train_dictionary(1024, samples) |
|
215 | d = zstd.train_dictionary(1024, samples) | |
213 |
|
216 | |||
214 | cctx = zstd.ZstdCompressor(dict_data=d, threads=2) |
|
217 | cctx = zstd.ZstdCompressor(dict_data=d, threads=2) | |
215 |
|
218 | |||
216 |
result = cctx.compress(b |
|
219 | result = cctx.compress(b"foo") | |
217 |
params = zstd.get_frame_parameters(result) |
|
220 | params = zstd.get_frame_parameters(result) | |
218 |
self.assertEqual(params.content_size, 3) |
|
221 | self.assertEqual(params.content_size, 3) | |
219 | self.assertEqual(params.dict_id, d.dict_id()) |
|
222 | self.assertEqual(params.dict_id, d.dict_id()) | |
220 |
|
223 | |||
221 |
self.assertEqual( |
|
224 | self.assertEqual( | |
222 | b'\x28\xb5\x2f\xfd\x23\x8f\x55\x0f\x70\x03\x19\x00\x00' |
|
225 | result, | |
223 | b'\x66\x6f\x6f') |
|
226 | b"\x28\xb5\x2f\xfd\x23\x8f\x55\x0f\x70\x03\x19\x00\x00" b"\x66\x6f\x6f", | |
|
227 | ) | |||
224 |
|
228 | |||
225 | def test_multithreaded_compression_params(self): |
|
229 | def test_multithreaded_compression_params(self): | |
226 | params = zstd.ZstdCompressionParameters.from_level(0, threads=2) |
|
230 | params = zstd.ZstdCompressionParameters.from_level(0, threads=2) | |
227 | cctx = zstd.ZstdCompressor(compression_params=params) |
|
231 | cctx = zstd.ZstdCompressor(compression_params=params) | |
228 |
|
232 | |||
229 |
result = cctx.compress(b |
|
233 | result = cctx.compress(b"foo") | |
230 |
params = zstd.get_frame_parameters(result) |
|
234 | params = zstd.get_frame_parameters(result) | |
231 |
self.assertEqual(params.content_size, 3) |
|
235 | self.assertEqual(params.content_size, 3) | |
232 |
|
236 | |||
233 | self.assertEqual(result, |
|
237 | self.assertEqual(result, b"\x28\xb5\x2f\xfd\x20\x03\x19\x00\x00\x66\x6f\x6f") | |
234 | b'\x28\xb5\x2f\xfd\x20\x03\x19\x00\x00\x66\x6f\x6f') |
|
|||
235 |
|
238 | |||
236 |
|
239 | |||
237 | @make_cffi |
|
240 | @make_cffi | |
238 |
class TestCompressor_compressobj( |
|
241 | class TestCompressor_compressobj(TestCase): | |
239 | def test_compressobj_empty(self): |
|
242 | def test_compressobj_empty(self): | |
240 | cctx = zstd.ZstdCompressor(level=1, write_content_size=False) |
|
243 | cctx = zstd.ZstdCompressor(level=1, write_content_size=False) | |
241 | cobj = cctx.compressobj() |
|
244 | cobj = cctx.compressobj() | |
242 |
self.assertEqual(cobj.compress(b |
|
245 | self.assertEqual(cobj.compress(b""), b"") | |
243 | self.assertEqual(cobj.flush(), |
|
246 | self.assertEqual(cobj.flush(), b"\x28\xb5\x2f\xfd\x00\x48\x01\x00\x00") | |
244 | b'\x28\xb5\x2f\xfd\x00\x48\x01\x00\x00') |
|
|||
245 |
|
247 | |||
246 | def test_input_types(self): |
|
248 | def test_input_types(self): | |
247 |
expected = b |
|
249 | expected = b"\x28\xb5\x2f\xfd\x00\x48\x19\x00\x00\x66\x6f\x6f" | |
248 | cctx = zstd.ZstdCompressor(level=1, write_content_size=False) |
|
250 | cctx = zstd.ZstdCompressor(level=1, write_content_size=False) | |
249 |
|
251 | |||
250 | mutable_array = bytearray(3) |
|
252 | mutable_array = bytearray(3) | |
251 |
mutable_array[:] = b |
|
253 | mutable_array[:] = b"foo" | |
252 |
|
254 | |||
253 | sources = [ |
|
255 | sources = [ | |
254 |
memoryview(b |
|
256 | memoryview(b"foo"), | |
255 |
bytearray(b |
|
257 | bytearray(b"foo"), | |
256 | mutable_array, |
|
258 | mutable_array, | |
257 | ] |
|
259 | ] | |
258 |
|
260 | |||
259 | for source in sources: |
|
261 | for source in sources: | |
260 | cobj = cctx.compressobj() |
|
262 | cobj = cctx.compressobj() | |
261 |
self.assertEqual(cobj.compress(source), b |
|
263 | self.assertEqual(cobj.compress(source), b"") | |
262 | self.assertEqual(cobj.flush(), expected) |
|
264 | self.assertEqual(cobj.flush(), expected) | |
263 |
|
265 | |||
264 | def test_compressobj_large(self): |
|
266 | def test_compressobj_large(self): | |
265 | chunks = [] |
|
267 | chunks = [] | |
266 | for i in range(255): |
|
268 | for i in range(255): | |
267 |
chunks.append(struct.Struct( |
|
269 | chunks.append(struct.Struct(">B").pack(i) * 16384) | |
268 |
|
270 | |||
269 | cctx = zstd.ZstdCompressor(level=3) |
|
271 | cctx = zstd.ZstdCompressor(level=3) | |
270 | cobj = cctx.compressobj() |
|
272 | cobj = cctx.compressobj() | |
271 |
|
273 | |||
272 |
result = cobj.compress(b |
|
274 | result = cobj.compress(b"".join(chunks)) + cobj.flush() | |
273 | self.assertEqual(len(result), 999) |
|
275 | self.assertEqual(len(result), 999) | |
274 |
self.assertEqual(result[0:4], b |
|
276 | self.assertEqual(result[0:4], b"\x28\xb5\x2f\xfd") | |
275 |
|
277 | |||
276 | params = zstd.get_frame_parameters(result) |
|
278 | params = zstd.get_frame_parameters(result) | |
277 | self.assertEqual(params.content_size, zstd.CONTENTSIZE_UNKNOWN) |
|
279 | self.assertEqual(params.content_size, zstd.CONTENTSIZE_UNKNOWN) | |
@@ -282,10 +284,10 b' class TestCompressor_compressobj(unittes' | |||||
282 | def test_write_checksum(self): |
|
284 | def test_write_checksum(self): | |
283 | cctx = zstd.ZstdCompressor(level=1) |
|
285 | cctx = zstd.ZstdCompressor(level=1) | |
284 | cobj = cctx.compressobj() |
|
286 | cobj = cctx.compressobj() | |
285 |
no_checksum = cobj.compress(b |
|
287 | no_checksum = cobj.compress(b"foobar") + cobj.flush() | |
286 | cctx = zstd.ZstdCompressor(level=1, write_checksum=True) |
|
288 | cctx = zstd.ZstdCompressor(level=1, write_checksum=True) | |
287 | cobj = cctx.compressobj() |
|
289 | cobj = cctx.compressobj() | |
288 |
with_checksum = cobj.compress(b |
|
290 | with_checksum = cobj.compress(b"foobar") + cobj.flush() | |
289 |
|
291 | |||
290 | no_params = zstd.get_frame_parameters(no_checksum) |
|
292 | no_params = zstd.get_frame_parameters(no_checksum) | |
291 | with_params = zstd.get_frame_parameters(with_checksum) |
|
293 | with_params = zstd.get_frame_parameters(with_checksum) | |
@@ -300,11 +302,11 b' class TestCompressor_compressobj(unittes' | |||||
300 |
|
302 | |||
301 | def test_write_content_size(self): |
|
303 | def test_write_content_size(self): | |
302 | cctx = zstd.ZstdCompressor(level=1) |
|
304 | cctx = zstd.ZstdCompressor(level=1) | |
303 |
cobj = cctx.compressobj(size=len(b |
|
305 | cobj = cctx.compressobj(size=len(b"foobar" * 256)) | |
304 |
with_size = cobj.compress(b |
|
306 | with_size = cobj.compress(b"foobar" * 256) + cobj.flush() | |
305 | cctx = zstd.ZstdCompressor(level=1, write_content_size=False) |
|
307 | cctx = zstd.ZstdCompressor(level=1, write_content_size=False) | |
306 |
cobj = cctx.compressobj(size=len(b |
|
308 | cobj = cctx.compressobj(size=len(b"foobar" * 256)) | |
307 |
no_size = cobj.compress(b |
|
309 | no_size = cobj.compress(b"foobar" * 256) + cobj.flush() | |
308 |
|
310 | |||
309 | no_params = zstd.get_frame_parameters(no_size) |
|
311 | no_params = zstd.get_frame_parameters(no_size) | |
310 | with_params = zstd.get_frame_parameters(with_size) |
|
312 | with_params = zstd.get_frame_parameters(with_size) | |
@@ -321,48 +323,53 b' class TestCompressor_compressobj(unittes' | |||||
321 | cctx = zstd.ZstdCompressor() |
|
323 | cctx = zstd.ZstdCompressor() | |
322 | cobj = cctx.compressobj() |
|
324 | cobj = cctx.compressobj() | |
323 |
|
325 | |||
324 |
cobj.compress(b |
|
326 | cobj.compress(b"foo") | |
325 | cobj.flush() |
|
327 | cobj.flush() | |
326 |
|
328 | |||
327 | with self.assertRaisesRegexp(zstd.ZstdError, r'cannot call compress\(\) after compressor'): |
|
329 | with self.assertRaisesRegex( | |
328 | cobj.compress(b'foo') |
|
330 | zstd.ZstdError, r"cannot call compress\(\) after compressor" | |
|
331 | ): | |||
|
332 | cobj.compress(b"foo") | |||
329 |
|
333 | |||
330 | with self.assertRaisesRegexp(zstd.ZstdError, 'compressor object already finished'): |
|
334 | with self.assertRaisesRegex( | |
|
335 | zstd.ZstdError, "compressor object already finished" | |||
|
336 | ): | |||
331 | cobj.flush() |
|
337 | cobj.flush() | |
332 |
|
338 | |||
333 | def test_flush_block_repeated(self): |
|
339 | def test_flush_block_repeated(self): | |
334 | cctx = zstd.ZstdCompressor(level=1) |
|
340 | cctx = zstd.ZstdCompressor(level=1) | |
335 | cobj = cctx.compressobj() |
|
341 | cobj = cctx.compressobj() | |
336 |
|
342 | |||
337 |
self.assertEqual(cobj.compress(b |
|
343 | self.assertEqual(cobj.compress(b"foo"), b"") | |
338 | self.assertEqual(cobj.flush(zstd.COMPRESSOBJ_FLUSH_BLOCK), |
|
344 | self.assertEqual( | |
339 | b'\x28\xb5\x2f\xfd\x00\x48\x18\x00\x00foo') |
|
345 | cobj.flush(zstd.COMPRESSOBJ_FLUSH_BLOCK), | |
340 | self.assertEqual(cobj.compress(b'bar'), b'') |
|
346 | b"\x28\xb5\x2f\xfd\x00\x48\x18\x00\x00foo", | |
|
347 | ) | |||
|
348 | self.assertEqual(cobj.compress(b"bar"), b"") | |||
341 | # 3 byte header plus content. |
|
349 | # 3 byte header plus content. | |
342 | self.assertEqual(cobj.flush(zstd.COMPRESSOBJ_FLUSH_BLOCK), |
|
350 | self.assertEqual(cobj.flush(zstd.COMPRESSOBJ_FLUSH_BLOCK), b"\x18\x00\x00bar") | |
343 | b'\x18\x00\x00bar') |
|
351 | self.assertEqual(cobj.flush(), b"\x01\x00\x00") | |
344 | self.assertEqual(cobj.flush(), b'\x01\x00\x00') |
|
|||
345 |
|
352 | |||
346 | def test_flush_empty_block(self): |
|
353 | def test_flush_empty_block(self): | |
347 | cctx = zstd.ZstdCompressor(write_checksum=True) |
|
354 | cctx = zstd.ZstdCompressor(write_checksum=True) | |
348 | cobj = cctx.compressobj() |
|
355 | cobj = cctx.compressobj() | |
349 |
|
356 | |||
350 |
cobj.compress(b |
|
357 | cobj.compress(b"foobar") | |
351 | cobj.flush(zstd.COMPRESSOBJ_FLUSH_BLOCK) |
|
358 | cobj.flush(zstd.COMPRESSOBJ_FLUSH_BLOCK) | |
352 | # No-op if no block is active (this is internal to zstd). |
|
359 | # No-op if no block is active (this is internal to zstd). | |
353 |
self.assertEqual(cobj.flush(zstd.COMPRESSOBJ_FLUSH_BLOCK), b |
|
360 | self.assertEqual(cobj.flush(zstd.COMPRESSOBJ_FLUSH_BLOCK), b"") | |
354 |
|
361 | |||
355 | trailing = cobj.flush() |
|
362 | trailing = cobj.flush() | |
356 | # 3 bytes block header + 4 bytes frame checksum |
|
363 | # 3 bytes block header + 4 bytes frame checksum | |
357 | self.assertEqual(len(trailing), 7) |
|
364 | self.assertEqual(len(trailing), 7) | |
358 | header = trailing[0:3] |
|
365 | header = trailing[0:3] | |
359 |
self.assertEqual(header, b |
|
366 | self.assertEqual(header, b"\x01\x00\x00") | |
360 |
|
367 | |||
361 | def test_multithreaded(self): |
|
368 | def test_multithreaded(self): | |
362 | source = io.BytesIO() |
|
369 | source = io.BytesIO() | |
363 |
source.write(b |
|
370 | source.write(b"a" * 1048576) | |
364 |
source.write(b |
|
371 | source.write(b"b" * 1048576) | |
365 |
source.write(b |
|
372 | source.write(b"c" * 1048576) | |
366 | source.seek(0) |
|
373 | source.seek(0) | |
367 |
|
374 | |||
368 | cctx = zstd.ZstdCompressor(level=1, threads=2) |
|
375 | cctx = zstd.ZstdCompressor(level=1, threads=2) | |
@@ -378,9 +385,9 b' class TestCompressor_compressobj(unittes' | |||||
378 |
|
385 | |||
379 | chunks.append(cobj.flush()) |
|
386 | chunks.append(cobj.flush()) | |
380 |
|
387 | |||
381 |
compressed = b |
|
388 | compressed = b"".join(chunks) | |
382 |
|
389 | |||
383 |
self.assertEqual(len(compressed), |
|
390 | self.assertEqual(len(compressed), 119) | |
384 |
|
391 | |||
385 | def test_frame_progression(self): |
|
392 | def test_frame_progression(self): | |
386 | cctx = zstd.ZstdCompressor() |
|
393 | cctx = zstd.ZstdCompressor() | |
@@ -389,7 +396,7 b' class TestCompressor_compressobj(unittes' | |||||
389 |
|
396 | |||
390 | cobj = cctx.compressobj() |
|
397 | cobj = cctx.compressobj() | |
391 |
|
398 | |||
392 |
cobj.compress(b |
|
399 | cobj.compress(b"foobar") | |
393 | self.assertEqual(cctx.frame_progression(), (6, 0, 0)) |
|
400 | self.assertEqual(cctx.frame_progression(), (6, 0, 0)) | |
394 |
|
401 | |||
395 | cobj.flush() |
|
402 | cobj.flush() | |
@@ -399,20 +406,20 b' class TestCompressor_compressobj(unittes' | |||||
399 | cctx = zstd.ZstdCompressor() |
|
406 | cctx = zstd.ZstdCompressor() | |
400 |
|
407 | |||
401 | cobj = cctx.compressobj(size=2) |
|
408 | cobj = cctx.compressobj(size=2) | |
402 |
with self.assertRaisesRegex |
|
409 | with self.assertRaisesRegex(zstd.ZstdError, "Src size is incorrect"): | |
403 |
cobj.compress(b |
|
410 | cobj.compress(b"foo") | |
404 |
|
411 | |||
405 | # Try another operation on this instance. |
|
412 | # Try another operation on this instance. | |
406 |
with self.assertRaisesRegex |
|
413 | with self.assertRaisesRegex(zstd.ZstdError, "Src size is incorrect"): | |
407 |
cobj.compress(b |
|
414 | cobj.compress(b"aa") | |
408 |
|
415 | |||
409 | # Try another operation on the compressor. |
|
416 | # Try another operation on the compressor. | |
410 | cctx.compressobj(size=4) |
|
417 | cctx.compressobj(size=4) | |
411 |
cctx.compress(b |
|
418 | cctx.compress(b"foobar") | |
412 |
|
419 | |||
413 |
|
420 | |||
414 | @make_cffi |
|
421 | @make_cffi | |
415 |
class TestCompressor_copy_stream( |
|
422 | class TestCompressor_copy_stream(TestCase): | |
416 | def test_no_read(self): |
|
423 | def test_no_read(self): | |
417 | source = object() |
|
424 | source = object() | |
418 | dest = io.BytesIO() |
|
425 | dest = io.BytesIO() | |
@@ -438,13 +445,12 b' class TestCompressor_copy_stream(unittes' | |||||
438 | self.assertEqual(int(r), 0) |
|
445 | self.assertEqual(int(r), 0) | |
439 | self.assertEqual(w, 9) |
|
446 | self.assertEqual(w, 9) | |
440 |
|
447 | |||
441 | self.assertEqual(dest.getvalue(), |
|
448 | self.assertEqual(dest.getvalue(), b"\x28\xb5\x2f\xfd\x00\x48\x01\x00\x00") | |
442 | b'\x28\xb5\x2f\xfd\x00\x48\x01\x00\x00') |
|
|||
443 |
|
449 | |||
444 | def test_large_data(self): |
|
450 | def test_large_data(self): | |
445 | source = io.BytesIO() |
|
451 | source = io.BytesIO() | |
446 | for i in range(255): |
|
452 | for i in range(255): | |
447 |
source.write(struct.Struct( |
|
453 | source.write(struct.Struct(">B").pack(i) * 16384) | |
448 | source.seek(0) |
|
454 | source.seek(0) | |
449 |
|
455 | |||
450 | dest = io.BytesIO() |
|
456 | dest = io.BytesIO() | |
@@ -461,7 +467,7 b' class TestCompressor_copy_stream(unittes' | |||||
461 | self.assertFalse(params.has_checksum) |
|
467 | self.assertFalse(params.has_checksum) | |
462 |
|
468 | |||
463 | def test_write_checksum(self): |
|
469 | def test_write_checksum(self): | |
464 |
source = io.BytesIO(b |
|
470 | source = io.BytesIO(b"foobar") | |
465 | no_checksum = io.BytesIO() |
|
471 | no_checksum = io.BytesIO() | |
466 |
|
472 | |||
467 | cctx = zstd.ZstdCompressor(level=1) |
|
473 | cctx = zstd.ZstdCompressor(level=1) | |
@@ -472,8 +478,7 b' class TestCompressor_copy_stream(unittes' | |||||
472 | cctx = zstd.ZstdCompressor(level=1, write_checksum=True) |
|
478 | cctx = zstd.ZstdCompressor(level=1, write_checksum=True) | |
473 | cctx.copy_stream(source, with_checksum) |
|
479 | cctx.copy_stream(source, with_checksum) | |
474 |
|
480 | |||
475 | self.assertEqual(len(with_checksum.getvalue()), |
|
481 | self.assertEqual(len(with_checksum.getvalue()), len(no_checksum.getvalue()) + 4) | |
476 | len(no_checksum.getvalue()) + 4) |
|
|||
477 |
|
482 | |||
478 | no_params = zstd.get_frame_parameters(no_checksum.getvalue()) |
|
483 | no_params = zstd.get_frame_parameters(no_checksum.getvalue()) | |
479 | with_params = zstd.get_frame_parameters(with_checksum.getvalue()) |
|
484 | with_params = zstd.get_frame_parameters(with_checksum.getvalue()) | |
@@ -485,7 +490,7 b' class TestCompressor_copy_stream(unittes' | |||||
485 | self.assertTrue(with_params.has_checksum) |
|
490 | self.assertTrue(with_params.has_checksum) | |
486 |
|
491 | |||
487 | def test_write_content_size(self): |
|
492 | def test_write_content_size(self): | |
488 |
source = io.BytesIO(b |
|
493 | source = io.BytesIO(b"foobar" * 256) | |
489 | no_size = io.BytesIO() |
|
494 | no_size = io.BytesIO() | |
490 |
|
495 | |||
491 | cctx = zstd.ZstdCompressor(level=1, write_content_size=False) |
|
496 | cctx = zstd.ZstdCompressor(level=1, write_content_size=False) | |
@@ -497,16 +502,14 b' class TestCompressor_copy_stream(unittes' | |||||
497 | cctx.copy_stream(source, with_size) |
|
502 | cctx.copy_stream(source, with_size) | |
498 |
|
503 | |||
499 | # Source content size is unknown, so no content size written. |
|
504 | # Source content size is unknown, so no content size written. | |
500 | self.assertEqual(len(with_size.getvalue()), |
|
505 | self.assertEqual(len(with_size.getvalue()), len(no_size.getvalue())) | |
501 | len(no_size.getvalue())) |
|
|||
502 |
|
506 | |||
503 | source.seek(0) |
|
507 | source.seek(0) | |
504 | with_size = io.BytesIO() |
|
508 | with_size = io.BytesIO() | |
505 | cctx.copy_stream(source, with_size, size=len(source.getvalue())) |
|
509 | cctx.copy_stream(source, with_size, size=len(source.getvalue())) | |
506 |
|
510 | |||
507 | # We specified source size, so content size header is present. |
|
511 | # We specified source size, so content size header is present. | |
508 | self.assertEqual(len(with_size.getvalue()), |
|
512 | self.assertEqual(len(with_size.getvalue()), len(no_size.getvalue()) + 1) | |
509 | len(no_size.getvalue()) + 1) |
|
|||
510 |
|
513 | |||
511 | no_params = zstd.get_frame_parameters(no_size.getvalue()) |
|
514 | no_params = zstd.get_frame_parameters(no_size.getvalue()) | |
512 | with_params = zstd.get_frame_parameters(with_size.getvalue()) |
|
515 | with_params = zstd.get_frame_parameters(with_size.getvalue()) | |
@@ -518,7 +521,7 b' class TestCompressor_copy_stream(unittes' | |||||
518 | self.assertFalse(with_params.has_checksum) |
|
521 | self.assertFalse(with_params.has_checksum) | |
519 |
|
522 | |||
520 | def test_read_write_size(self): |
|
523 | def test_read_write_size(self): | |
521 |
source = OpCountingBytesIO(b |
|
524 | source = OpCountingBytesIO(b"foobarfoobar") | |
522 | dest = OpCountingBytesIO() |
|
525 | dest = OpCountingBytesIO() | |
523 | cctx = zstd.ZstdCompressor() |
|
526 | cctx = zstd.ZstdCompressor() | |
524 | r, w = cctx.copy_stream(source, dest, read_size=1, write_size=1) |
|
527 | r, w = cctx.copy_stream(source, dest, read_size=1, write_size=1) | |
@@ -530,16 +533,16 b' class TestCompressor_copy_stream(unittes' | |||||
530 |
|
533 | |||
531 | def test_multithreaded(self): |
|
534 | def test_multithreaded(self): | |
532 | source = io.BytesIO() |
|
535 | source = io.BytesIO() | |
533 |
source.write(b |
|
536 | source.write(b"a" * 1048576) | |
534 |
source.write(b |
|
537 | source.write(b"b" * 1048576) | |
535 |
source.write(b |
|
538 | source.write(b"c" * 1048576) | |
536 | source.seek(0) |
|
539 | source.seek(0) | |
537 |
|
540 | |||
538 | dest = io.BytesIO() |
|
541 | dest = io.BytesIO() | |
539 | cctx = zstd.ZstdCompressor(threads=2, write_content_size=False) |
|
542 | cctx = zstd.ZstdCompressor(threads=2, write_content_size=False) | |
540 | r, w = cctx.copy_stream(source, dest) |
|
543 | r, w = cctx.copy_stream(source, dest) | |
541 | self.assertEqual(r, 3145728) |
|
544 | self.assertEqual(r, 3145728) | |
542 |
self.assertEqual(w, |
|
545 | self.assertEqual(w, 111) | |
543 |
|
546 | |||
544 | params = zstd.get_frame_parameters(dest.getvalue()) |
|
547 | params = zstd.get_frame_parameters(dest.getvalue()) | |
545 | self.assertEqual(params.content_size, zstd.CONTENTSIZE_UNKNOWN) |
|
548 | self.assertEqual(params.content_size, zstd.CONTENTSIZE_UNKNOWN) | |
@@ -559,15 +562,15 b' class TestCompressor_copy_stream(unittes' | |||||
559 |
|
562 | |||
560 | def test_bad_size(self): |
|
563 | def test_bad_size(self): | |
561 | source = io.BytesIO() |
|
564 | source = io.BytesIO() | |
562 |
source.write(b |
|
565 | source.write(b"a" * 32768) | |
563 |
source.write(b |
|
566 | source.write(b"b" * 32768) | |
564 | source.seek(0) |
|
567 | source.seek(0) | |
565 |
|
568 | |||
566 | dest = io.BytesIO() |
|
569 | dest = io.BytesIO() | |
567 |
|
570 | |||
568 | cctx = zstd.ZstdCompressor() |
|
571 | cctx = zstd.ZstdCompressor() | |
569 |
|
572 | |||
570 |
with self.assertRaisesRegex |
|
573 | with self.assertRaisesRegex(zstd.ZstdError, "Src size is incorrect"): | |
571 | cctx.copy_stream(source, dest, size=42) |
|
574 | cctx.copy_stream(source, dest, size=42) | |
572 |
|
575 | |||
573 | # Try another operation on this compressor. |
|
576 | # Try another operation on this compressor. | |
@@ -577,31 +580,31 b' class TestCompressor_copy_stream(unittes' | |||||
577 |
|
580 | |||
578 |
|
581 | |||
579 | @make_cffi |
|
582 | @make_cffi | |
580 |
class TestCompressor_stream_reader( |
|
583 | class TestCompressor_stream_reader(TestCase): | |
581 | def test_context_manager(self): |
|
584 | def test_context_manager(self): | |
582 | cctx = zstd.ZstdCompressor() |
|
585 | cctx = zstd.ZstdCompressor() | |
583 |
|
586 | |||
584 |
with cctx.stream_reader(b |
|
587 | with cctx.stream_reader(b"foo") as reader: | |
585 |
with self.assertRaisesRegex |
|
588 | with self.assertRaisesRegex(ValueError, "cannot __enter__ multiple times"): | |
586 | with reader as reader2: |
|
589 | with reader as reader2: | |
587 | pass |
|
590 | pass | |
588 |
|
591 | |||
589 | def test_no_context_manager(self): |
|
592 | def test_no_context_manager(self): | |
590 | cctx = zstd.ZstdCompressor() |
|
593 | cctx = zstd.ZstdCompressor() | |
591 |
|
594 | |||
592 |
reader = cctx.stream_reader(b |
|
595 | reader = cctx.stream_reader(b"foo") | |
593 | reader.read(4) |
|
596 | reader.read(4) | |
594 | self.assertFalse(reader.closed) |
|
597 | self.assertFalse(reader.closed) | |
595 |
|
598 | |||
596 | reader.close() |
|
599 | reader.close() | |
597 | self.assertTrue(reader.closed) |
|
600 | self.assertTrue(reader.closed) | |
598 |
with self.assertRaisesRegex |
|
601 | with self.assertRaisesRegex(ValueError, "stream is closed"): | |
599 | reader.read(1) |
|
602 | reader.read(1) | |
600 |
|
603 | |||
601 | def test_not_implemented(self): |
|
604 | def test_not_implemented(self): | |
602 | cctx = zstd.ZstdCompressor() |
|
605 | cctx = zstd.ZstdCompressor() | |
603 |
|
606 | |||
604 |
with cctx.stream_reader(b |
|
607 | with cctx.stream_reader(b"foo" * 60) as reader: | |
605 | with self.assertRaises(io.UnsupportedOperation): |
|
608 | with self.assertRaises(io.UnsupportedOperation): | |
606 | reader.readline() |
|
609 | reader.readline() | |
607 |
|
610 | |||
@@ -618,12 +621,12 b' class TestCompressor_stream_reader(unitt' | |||||
618 | reader.writelines([]) |
|
621 | reader.writelines([]) | |
619 |
|
622 | |||
620 | with self.assertRaises(OSError): |
|
623 | with self.assertRaises(OSError): | |
621 |
reader.write(b |
|
624 | reader.write(b"foo") | |
622 |
|
625 | |||
623 | def test_constant_methods(self): |
|
626 | def test_constant_methods(self): | |
624 | cctx = zstd.ZstdCompressor() |
|
627 | cctx = zstd.ZstdCompressor() | |
625 |
|
628 | |||
626 |
with cctx.stream_reader(b |
|
629 | with cctx.stream_reader(b"boo") as reader: | |
627 | self.assertTrue(reader.readable()) |
|
630 | self.assertTrue(reader.readable()) | |
628 | self.assertFalse(reader.writable()) |
|
631 | self.assertFalse(reader.writable()) | |
629 | self.assertFalse(reader.seekable()) |
|
632 | self.assertFalse(reader.seekable()) | |
@@ -637,27 +640,29 b' class TestCompressor_stream_reader(unitt' | |||||
637 | def test_read_closed(self): |
|
640 | def test_read_closed(self): | |
638 | cctx = zstd.ZstdCompressor() |
|
641 | cctx = zstd.ZstdCompressor() | |
639 |
|
642 | |||
640 |
with cctx.stream_reader(b |
|
643 | with cctx.stream_reader(b"foo" * 60) as reader: | |
641 | reader.close() |
|
644 | reader.close() | |
642 | self.assertTrue(reader.closed) |
|
645 | self.assertTrue(reader.closed) | |
643 |
with self.assertRaisesRegex |
|
646 | with self.assertRaisesRegex(ValueError, "stream is closed"): | |
644 | reader.read(10) |
|
647 | reader.read(10) | |
645 |
|
648 | |||
646 | def test_read_sizes(self): |
|
649 | def test_read_sizes(self): | |
647 | cctx = zstd.ZstdCompressor() |
|
650 | cctx = zstd.ZstdCompressor() | |
648 |
foo = cctx.compress(b |
|
651 | foo = cctx.compress(b"foo") | |
649 |
|
652 | |||
650 |
with cctx.stream_reader(b |
|
653 | with cctx.stream_reader(b"foo") as reader: | |
651 | with self.assertRaisesRegexp(ValueError, 'cannot read negative amounts less than -1'): |
|
654 | with self.assertRaisesRegex( | |
|
655 | ValueError, "cannot read negative amounts less than -1" | |||
|
656 | ): | |||
652 | reader.read(-2) |
|
657 | reader.read(-2) | |
653 |
|
658 | |||
654 |
self.assertEqual(reader.read(0), b |
|
659 | self.assertEqual(reader.read(0), b"") | |
655 | self.assertEqual(reader.read(), foo) |
|
660 | self.assertEqual(reader.read(), foo) | |
656 |
|
661 | |||
657 | def test_read_buffer(self): |
|
662 | def test_read_buffer(self): | |
658 | cctx = zstd.ZstdCompressor() |
|
663 | cctx = zstd.ZstdCompressor() | |
659 |
|
664 | |||
660 |
source = b |
|
665 | source = b"".join([b"foo" * 60, b"bar" * 60, b"baz" * 60]) | |
661 | frame = cctx.compress(source) |
|
666 | frame = cctx.compress(source) | |
662 |
|
667 | |||
663 | with cctx.stream_reader(source) as reader: |
|
668 | with cctx.stream_reader(source) as reader: | |
@@ -667,13 +672,13 b' class TestCompressor_stream_reader(unitt' | |||||
667 | result = reader.read(8192) |
|
672 | result = reader.read(8192) | |
668 | self.assertEqual(result, frame) |
|
673 | self.assertEqual(result, frame) | |
669 | self.assertEqual(reader.tell(), len(result)) |
|
674 | self.assertEqual(reader.tell(), len(result)) | |
670 |
self.assertEqual(reader.read(), b |
|
675 | self.assertEqual(reader.read(), b"") | |
671 | self.assertEqual(reader.tell(), len(result)) |
|
676 | self.assertEqual(reader.tell(), len(result)) | |
672 |
|
677 | |||
673 | def test_read_buffer_small_chunks(self): |
|
678 | def test_read_buffer_small_chunks(self): | |
674 | cctx = zstd.ZstdCompressor() |
|
679 | cctx = zstd.ZstdCompressor() | |
675 |
|
680 | |||
676 |
source = b |
|
681 | source = b"foo" * 60 | |
677 | chunks = [] |
|
682 | chunks = [] | |
678 |
|
683 | |||
679 | with cctx.stream_reader(source) as reader: |
|
684 | with cctx.stream_reader(source) as reader: | |
@@ -687,12 +692,12 b' class TestCompressor_stream_reader(unitt' | |||||
687 | chunks.append(chunk) |
|
692 | chunks.append(chunk) | |
688 | self.assertEqual(reader.tell(), sum(map(len, chunks))) |
|
693 | self.assertEqual(reader.tell(), sum(map(len, chunks))) | |
689 |
|
694 | |||
690 |
self.assertEqual(b |
|
695 | self.assertEqual(b"".join(chunks), cctx.compress(source)) | |
691 |
|
696 | |||
692 | def test_read_stream(self): |
|
697 | def test_read_stream(self): | |
693 | cctx = zstd.ZstdCompressor() |
|
698 | cctx = zstd.ZstdCompressor() | |
694 |
|
699 | |||
695 |
source = b |
|
700 | source = b"".join([b"foo" * 60, b"bar" * 60, b"baz" * 60]) | |
696 | frame = cctx.compress(source) |
|
701 | frame = cctx.compress(source) | |
697 |
|
702 | |||
698 | with cctx.stream_reader(io.BytesIO(source), size=len(source)) as reader: |
|
703 | with cctx.stream_reader(io.BytesIO(source), size=len(source)) as reader: | |
@@ -701,13 +706,13 b' class TestCompressor_stream_reader(unitt' | |||||
701 | chunk = reader.read(8192) |
|
706 | chunk = reader.read(8192) | |
702 | self.assertEqual(chunk, frame) |
|
707 | self.assertEqual(chunk, frame) | |
703 | self.assertEqual(reader.tell(), len(chunk)) |
|
708 | self.assertEqual(reader.tell(), len(chunk)) | |
704 |
self.assertEqual(reader.read(), b |
|
709 | self.assertEqual(reader.read(), b"") | |
705 | self.assertEqual(reader.tell(), len(chunk)) |
|
710 | self.assertEqual(reader.tell(), len(chunk)) | |
706 |
|
711 | |||
707 | def test_read_stream_small_chunks(self): |
|
712 | def test_read_stream_small_chunks(self): | |
708 | cctx = zstd.ZstdCompressor() |
|
713 | cctx = zstd.ZstdCompressor() | |
709 |
|
714 | |||
710 |
source = b |
|
715 | source = b"foo" * 60 | |
711 | chunks = [] |
|
716 | chunks = [] | |
712 |
|
717 | |||
713 | with cctx.stream_reader(io.BytesIO(source), size=len(source)) as reader: |
|
718 | with cctx.stream_reader(io.BytesIO(source), size=len(source)) as reader: | |
@@ -721,25 +726,25 b' class TestCompressor_stream_reader(unitt' | |||||
721 | chunks.append(chunk) |
|
726 | chunks.append(chunk) | |
722 | self.assertEqual(reader.tell(), sum(map(len, chunks))) |
|
727 | self.assertEqual(reader.tell(), sum(map(len, chunks))) | |
723 |
|
728 | |||
724 |
self.assertEqual(b |
|
729 | self.assertEqual(b"".join(chunks), cctx.compress(source)) | |
725 |
|
730 | |||
726 | def test_read_after_exit(self): |
|
731 | def test_read_after_exit(self): | |
727 | cctx = zstd.ZstdCompressor() |
|
732 | cctx = zstd.ZstdCompressor() | |
728 |
|
733 | |||
729 |
with cctx.stream_reader(b |
|
734 | with cctx.stream_reader(b"foo" * 60) as reader: | |
730 | while reader.read(8192): |
|
735 | while reader.read(8192): | |
731 | pass |
|
736 | pass | |
732 |
|
737 | |||
733 |
with self.assertRaisesRegex |
|
738 | with self.assertRaisesRegex(ValueError, "stream is closed"): | |
734 | reader.read(10) |
|
739 | reader.read(10) | |
735 |
|
740 | |||
736 | def test_bad_size(self): |
|
741 | def test_bad_size(self): | |
737 | cctx = zstd.ZstdCompressor() |
|
742 | cctx = zstd.ZstdCompressor() | |
738 |
|
743 | |||
739 |
source = io.BytesIO(b |
|
744 | source = io.BytesIO(b"foobar") | |
740 |
|
745 | |||
741 | with cctx.stream_reader(source, size=2) as reader: |
|
746 | with cctx.stream_reader(source, size=2) as reader: | |
742 |
with self.assertRaisesRegex |
|
747 | with self.assertRaisesRegex(zstd.ZstdError, "Src size is incorrect"): | |
743 | reader.read(10) |
|
748 | reader.read(10) | |
744 |
|
749 | |||
745 | # Try another compression operation. |
|
750 | # Try another compression operation. | |
@@ -748,36 +753,36 b' class TestCompressor_stream_reader(unitt' | |||||
748 |
|
753 | |||
749 | def test_readall(self): |
|
754 | def test_readall(self): | |
750 | cctx = zstd.ZstdCompressor() |
|
755 | cctx = zstd.ZstdCompressor() | |
751 |
frame = cctx.compress(b |
|
756 | frame = cctx.compress(b"foo" * 1024) | |
752 |
|
757 | |||
753 |
reader = cctx.stream_reader(b |
|
758 | reader = cctx.stream_reader(b"foo" * 1024) | |
754 | self.assertEqual(reader.readall(), frame) |
|
759 | self.assertEqual(reader.readall(), frame) | |
755 |
|
760 | |||
756 | def test_readinto(self): |
|
761 | def test_readinto(self): | |
757 | cctx = zstd.ZstdCompressor() |
|
762 | cctx = zstd.ZstdCompressor() | |
758 |
foo = cctx.compress(b |
|
763 | foo = cctx.compress(b"foo") | |
759 |
|
764 | |||
760 |
reader = cctx.stream_reader(b |
|
765 | reader = cctx.stream_reader(b"foo") | |
761 | with self.assertRaises(Exception): |
|
766 | with self.assertRaises(Exception): | |
762 |
reader.readinto(b |
|
767 | reader.readinto(b"foobar") | |
763 |
|
768 | |||
764 | # readinto() with sufficiently large destination. |
|
769 | # readinto() with sufficiently large destination. | |
765 | b = bytearray(1024) |
|
770 | b = bytearray(1024) | |
766 |
reader = cctx.stream_reader(b |
|
771 | reader = cctx.stream_reader(b"foo") | |
767 | self.assertEqual(reader.readinto(b), len(foo)) |
|
772 | self.assertEqual(reader.readinto(b), len(foo)) | |
768 | self.assertEqual(b[0:len(foo)], foo) |
|
773 | self.assertEqual(b[0 : len(foo)], foo) | |
769 | self.assertEqual(reader.readinto(b), 0) |
|
774 | self.assertEqual(reader.readinto(b), 0) | |
770 | self.assertEqual(b[0:len(foo)], foo) |
|
775 | self.assertEqual(b[0 : len(foo)], foo) | |
771 |
|
776 | |||
772 | # readinto() with small reads. |
|
777 | # readinto() with small reads. | |
773 | b = bytearray(1024) |
|
778 | b = bytearray(1024) | |
774 |
reader = cctx.stream_reader(b |
|
779 | reader = cctx.stream_reader(b"foo", read_size=1) | |
775 | self.assertEqual(reader.readinto(b), len(foo)) |
|
780 | self.assertEqual(reader.readinto(b), len(foo)) | |
776 | self.assertEqual(b[0:len(foo)], foo) |
|
781 | self.assertEqual(b[0 : len(foo)], foo) | |
777 |
|
782 | |||
778 | # Too small destination buffer. |
|
783 | # Too small destination buffer. | |
779 | b = bytearray(2) |
|
784 | b = bytearray(2) | |
780 |
reader = cctx.stream_reader(b |
|
785 | reader = cctx.stream_reader(b"foo") | |
781 | self.assertEqual(reader.readinto(b), 2) |
|
786 | self.assertEqual(reader.readinto(b), 2) | |
782 | self.assertEqual(b[:], foo[0:2]) |
|
787 | self.assertEqual(b[:], foo[0:2]) | |
783 | self.assertEqual(reader.readinto(b), 2) |
|
788 | self.assertEqual(reader.readinto(b), 2) | |
@@ -787,41 +792,41 b' class TestCompressor_stream_reader(unitt' | |||||
787 |
|
792 | |||
788 | def test_readinto1(self): |
|
793 | def test_readinto1(self): | |
789 | cctx = zstd.ZstdCompressor() |
|
794 | cctx = zstd.ZstdCompressor() | |
790 |
foo = b |
|
795 | foo = b"".join(cctx.read_to_iter(io.BytesIO(b"foo"))) | |
791 |
|
796 | |||
792 |
reader = cctx.stream_reader(b |
|
797 | reader = cctx.stream_reader(b"foo") | |
793 | with self.assertRaises(Exception): |
|
798 | with self.assertRaises(Exception): | |
794 |
reader.readinto1(b |
|
799 | reader.readinto1(b"foobar") | |
795 |
|
800 | |||
796 | b = bytearray(1024) |
|
801 | b = bytearray(1024) | |
797 |
source = OpCountingBytesIO(b |
|
802 | source = OpCountingBytesIO(b"foo") | |
798 | reader = cctx.stream_reader(source) |
|
803 | reader = cctx.stream_reader(source) | |
799 | self.assertEqual(reader.readinto1(b), len(foo)) |
|
804 | self.assertEqual(reader.readinto1(b), len(foo)) | |
800 | self.assertEqual(b[0:len(foo)], foo) |
|
805 | self.assertEqual(b[0 : len(foo)], foo) | |
801 | self.assertEqual(source._read_count, 2) |
|
806 | self.assertEqual(source._read_count, 2) | |
802 |
|
807 | |||
803 | # readinto1() with small reads. |
|
808 | # readinto1() with small reads. | |
804 | b = bytearray(1024) |
|
809 | b = bytearray(1024) | |
805 |
source = OpCountingBytesIO(b |
|
810 | source = OpCountingBytesIO(b"foo") | |
806 | reader = cctx.stream_reader(source, read_size=1) |
|
811 | reader = cctx.stream_reader(source, read_size=1) | |
807 | self.assertEqual(reader.readinto1(b), len(foo)) |
|
812 | self.assertEqual(reader.readinto1(b), len(foo)) | |
808 | self.assertEqual(b[0:len(foo)], foo) |
|
813 | self.assertEqual(b[0 : len(foo)], foo) | |
809 | self.assertEqual(source._read_count, 4) |
|
814 | self.assertEqual(source._read_count, 4) | |
810 |
|
815 | |||
811 | def test_read1(self): |
|
816 | def test_read1(self): | |
812 | cctx = zstd.ZstdCompressor() |
|
817 | cctx = zstd.ZstdCompressor() | |
813 |
foo = b |
|
818 | foo = b"".join(cctx.read_to_iter(io.BytesIO(b"foo"))) | |
814 |
|
819 | |||
815 |
b = OpCountingBytesIO(b |
|
820 | b = OpCountingBytesIO(b"foo") | |
816 | reader = cctx.stream_reader(b) |
|
821 | reader = cctx.stream_reader(b) | |
817 |
|
822 | |||
818 | self.assertEqual(reader.read1(), foo) |
|
823 | self.assertEqual(reader.read1(), foo) | |
819 | self.assertEqual(b._read_count, 2) |
|
824 | self.assertEqual(b._read_count, 2) | |
820 |
|
825 | |||
821 |
b = OpCountingBytesIO(b |
|
826 | b = OpCountingBytesIO(b"foo") | |
822 | reader = cctx.stream_reader(b) |
|
827 | reader = cctx.stream_reader(b) | |
823 |
|
828 | |||
824 |
self.assertEqual(reader.read1(0), b |
|
829 | self.assertEqual(reader.read1(0), b"") | |
825 | self.assertEqual(reader.read1(2), foo[0:2]) |
|
830 | self.assertEqual(reader.read1(2), foo[0:2]) | |
826 | self.assertEqual(b._read_count, 2) |
|
831 | self.assertEqual(b._read_count, 2) | |
827 | self.assertEqual(reader.read1(2), foo[2:4]) |
|
832 | self.assertEqual(reader.read1(2), foo[2:4]) | |
@@ -829,7 +834,7 b' class TestCompressor_stream_reader(unitt' | |||||
829 |
|
834 | |||
830 |
|
835 | |||
831 | @make_cffi |
|
836 | @make_cffi | |
832 |
class TestCompressor_stream_writer( |
|
837 | class TestCompressor_stream_writer(TestCase): | |
833 | def test_io_api(self): |
|
838 | def test_io_api(self): | |
834 | buffer = io.BytesIO() |
|
839 | buffer = io.BytesIO() | |
835 | cctx = zstd.ZstdCompressor() |
|
840 | cctx = zstd.ZstdCompressor() | |
@@ -899,7 +904,7 b' class TestCompressor_stream_writer(unitt' | |||||
899 | self.assertFalse(writer.closed) |
|
904 | self.assertFalse(writer.closed) | |
900 |
|
905 | |||
901 | def test_fileno_file(self): |
|
906 | def test_fileno_file(self): | |
902 |
with tempfile.TemporaryFile( |
|
907 | with tempfile.TemporaryFile("wb") as tf: | |
903 | cctx = zstd.ZstdCompressor() |
|
908 | cctx = zstd.ZstdCompressor() | |
904 | writer = cctx.stream_writer(tf) |
|
909 | writer = cctx.stream_writer(tf) | |
905 |
|
910 | |||
@@ -910,33 +915,35 b' class TestCompressor_stream_writer(unitt' | |||||
910 | cctx = zstd.ZstdCompressor(level=1) |
|
915 | cctx = zstd.ZstdCompressor(level=1) | |
911 | writer = cctx.stream_writer(buffer) |
|
916 | writer = cctx.stream_writer(buffer) | |
912 |
|
917 | |||
913 |
writer.write(b |
|
918 | writer.write(b"foo" * 1024) | |
914 | self.assertFalse(writer.closed) |
|
919 | self.assertFalse(writer.closed) | |
915 | self.assertFalse(buffer.closed) |
|
920 | self.assertFalse(buffer.closed) | |
916 | writer.close() |
|
921 | writer.close() | |
917 | self.assertTrue(writer.closed) |
|
922 | self.assertTrue(writer.closed) | |
918 | self.assertTrue(buffer.closed) |
|
923 | self.assertTrue(buffer.closed) | |
919 |
|
924 | |||
920 |
with self.assertRaisesRegex |
|
925 | with self.assertRaisesRegex(ValueError, "stream is closed"): | |
921 |
writer.write(b |
|
926 | writer.write(b"foo") | |
922 |
|
927 | |||
923 |
with self.assertRaisesRegex |
|
928 | with self.assertRaisesRegex(ValueError, "stream is closed"): | |
924 | writer.flush() |
|
929 | writer.flush() | |
925 |
|
930 | |||
926 |
with self.assertRaisesRegex |
|
931 | with self.assertRaisesRegex(ValueError, "stream is closed"): | |
927 | with writer: |
|
932 | with writer: | |
928 | pass |
|
933 | pass | |
929 |
|
934 | |||
930 |
self.assertEqual( |
|
935 | self.assertEqual( | |
931 | b'\x28\xb5\x2f\xfd\x00\x48\x55\x00\x00\x18\x66\x6f' |
|
936 | buffer.getvalue(), | |
932 | b'\x6f\x01\x00\xfa\xd3\x77\x43') |
|
937 | b"\x28\xb5\x2f\xfd\x00\x48\x55\x00\x00\x18\x66\x6f" | |
|
938 | b"\x6f\x01\x00\xfa\xd3\x77\x43", | |||
|
939 | ) | |||
933 |
|
940 | |||
934 | # Context manager exit should close stream. |
|
941 | # Context manager exit should close stream. | |
935 | buffer = io.BytesIO() |
|
942 | buffer = io.BytesIO() | |
936 | writer = cctx.stream_writer(buffer) |
|
943 | writer = cctx.stream_writer(buffer) | |
937 |
|
944 | |||
938 | with writer: |
|
945 | with writer: | |
939 |
writer.write(b |
|
946 | writer.write(b"foo") | |
940 |
|
947 | |||
941 | self.assertTrue(writer.closed) |
|
948 | self.assertTrue(writer.closed) | |
942 |
|
949 | |||
@@ -944,10 +951,10 b' class TestCompressor_stream_writer(unitt' | |||||
944 | buffer = NonClosingBytesIO() |
|
951 | buffer = NonClosingBytesIO() | |
945 | cctx = zstd.ZstdCompressor(level=1, write_content_size=False) |
|
952 | cctx = zstd.ZstdCompressor(level=1, write_content_size=False) | |
946 | with cctx.stream_writer(buffer) as compressor: |
|
953 | with cctx.stream_writer(buffer) as compressor: | |
947 |
compressor.write(b |
|
954 | compressor.write(b"") | |
948 |
|
955 | |||
949 | result = buffer.getvalue() |
|
956 | result = buffer.getvalue() | |
950 |
self.assertEqual(result, b |
|
957 | self.assertEqual(result, b"\x28\xb5\x2f\xfd\x00\x48\x01\x00\x00") | |
951 |
|
958 | |||
952 | params = zstd.get_frame_parameters(result) |
|
959 | params = zstd.get_frame_parameters(result) | |
953 | self.assertEqual(params.content_size, zstd.CONTENTSIZE_UNKNOWN) |
|
960 | self.assertEqual(params.content_size, zstd.CONTENTSIZE_UNKNOWN) | |
@@ -958,11 +965,11 b' class TestCompressor_stream_writer(unitt' | |||||
958 | # Test without context manager. |
|
965 | # Test without context manager. | |
959 | buffer = io.BytesIO() |
|
966 | buffer = io.BytesIO() | |
960 | compressor = cctx.stream_writer(buffer) |
|
967 | compressor = cctx.stream_writer(buffer) | |
961 |
self.assertEqual(compressor.write(b |
|
968 | self.assertEqual(compressor.write(b""), 0) | |
962 |
self.assertEqual(buffer.getvalue(), b |
|
969 | self.assertEqual(buffer.getvalue(), b"") | |
963 | self.assertEqual(compressor.flush(zstd.FLUSH_FRAME), 9) |
|
970 | self.assertEqual(compressor.flush(zstd.FLUSH_FRAME), 9) | |
964 | result = buffer.getvalue() |
|
971 | result = buffer.getvalue() | |
965 |
self.assertEqual(result, b |
|
972 | self.assertEqual(result, b"\x28\xb5\x2f\xfd\x00\x48\x01\x00\x00") | |
966 |
|
973 | |||
967 | params = zstd.get_frame_parameters(result) |
|
974 | params = zstd.get_frame_parameters(result) | |
968 | self.assertEqual(params.content_size, zstd.CONTENTSIZE_UNKNOWN) |
|
975 | self.assertEqual(params.content_size, zstd.CONTENTSIZE_UNKNOWN) | |
@@ -972,18 +979,18 b' class TestCompressor_stream_writer(unitt' | |||||
972 |
|
979 | |||
973 | # Test write_return_read=True |
|
980 | # Test write_return_read=True | |
974 | compressor = cctx.stream_writer(buffer, write_return_read=True) |
|
981 | compressor = cctx.stream_writer(buffer, write_return_read=True) | |
975 |
self.assertEqual(compressor.write(b |
|
982 | self.assertEqual(compressor.write(b""), 0) | |
976 |
|
983 | |||
977 | def test_input_types(self): |
|
984 | def test_input_types(self): | |
978 |
expected = b |
|
985 | expected = b"\x28\xb5\x2f\xfd\x00\x48\x19\x00\x00\x66\x6f\x6f" | |
979 | cctx = zstd.ZstdCompressor(level=1) |
|
986 | cctx = zstd.ZstdCompressor(level=1) | |
980 |
|
987 | |||
981 | mutable_array = bytearray(3) |
|
988 | mutable_array = bytearray(3) | |
982 |
mutable_array[:] = b |
|
989 | mutable_array[:] = b"foo" | |
983 |
|
990 | |||
984 | sources = [ |
|
991 | sources = [ | |
985 |
memoryview(b |
|
992 | memoryview(b"foo"), | |
986 |
bytearray(b |
|
993 | bytearray(b"foo"), | |
987 | mutable_array, |
|
994 | mutable_array, | |
988 | ] |
|
995 | ] | |
989 |
|
996 | |||
@@ -1001,51 +1008,55 b' class TestCompressor_stream_writer(unitt' | |||||
1001 | buffer = NonClosingBytesIO() |
|
1008 | buffer = NonClosingBytesIO() | |
1002 | cctx = zstd.ZstdCompressor(level=5) |
|
1009 | cctx = zstd.ZstdCompressor(level=5) | |
1003 | with cctx.stream_writer(buffer) as compressor: |
|
1010 | with cctx.stream_writer(buffer) as compressor: | |
1004 |
self.assertEqual(compressor.write(b |
|
1011 | self.assertEqual(compressor.write(b"foo"), 0) | |
1005 |
self.assertEqual(compressor.write(b |
|
1012 | self.assertEqual(compressor.write(b"bar"), 0) | |
1006 |
self.assertEqual(compressor.write(b |
|
1013 | self.assertEqual(compressor.write(b"x" * 8192), 0) | |
1007 |
|
1014 | |||
1008 | result = buffer.getvalue() |
|
1015 | result = buffer.getvalue() | |
1009 |
self.assertEqual( |
|
1016 | self.assertEqual( | |
1010 | b'\x28\xb5\x2f\xfd\x00\x58\x75\x00\x00\x38\x66\x6f' |
|
1017 | result, | |
1011 | b'\x6f\x62\x61\x72\x78\x01\x00\xfc\xdf\x03\x23') |
|
1018 | b"\x28\xb5\x2f\xfd\x00\x58\x75\x00\x00\x38\x66\x6f" | |
|
1019 | b"\x6f\x62\x61\x72\x78\x01\x00\xfc\xdf\x03\x23", | |||
|
1020 | ) | |||
1012 |
|
1021 | |||
1013 | # Test without context manager. |
|
1022 | # Test without context manager. | |
1014 | buffer = io.BytesIO() |
|
1023 | buffer = io.BytesIO() | |
1015 | compressor = cctx.stream_writer(buffer) |
|
1024 | compressor = cctx.stream_writer(buffer) | |
1016 |
self.assertEqual(compressor.write(b |
|
1025 | self.assertEqual(compressor.write(b"foo"), 0) | |
1017 |
self.assertEqual(compressor.write(b |
|
1026 | self.assertEqual(compressor.write(b"bar"), 0) | |
1018 |
self.assertEqual(compressor.write(b |
|
1027 | self.assertEqual(compressor.write(b"x" * 8192), 0) | |
1019 | self.assertEqual(compressor.flush(zstd.FLUSH_FRAME), 23) |
|
1028 | self.assertEqual(compressor.flush(zstd.FLUSH_FRAME), 23) | |
1020 | result = buffer.getvalue() |
|
1029 | result = buffer.getvalue() | |
1021 |
self.assertEqual( |
|
1030 | self.assertEqual( | |
1022 | b'\x28\xb5\x2f\xfd\x00\x58\x75\x00\x00\x38\x66\x6f' |
|
1031 | result, | |
1023 | b'\x6f\x62\x61\x72\x78\x01\x00\xfc\xdf\x03\x23') |
|
1032 | b"\x28\xb5\x2f\xfd\x00\x58\x75\x00\x00\x38\x66\x6f" | |
|
1033 | b"\x6f\x62\x61\x72\x78\x01\x00\xfc\xdf\x03\x23", | |||
|
1034 | ) | |||
1024 |
|
1035 | |||
1025 | # Test with write_return_read=True. |
|
1036 | # Test with write_return_read=True. | |
1026 | compressor = cctx.stream_writer(buffer, write_return_read=True) |
|
1037 | compressor = cctx.stream_writer(buffer, write_return_read=True) | |
1027 |
self.assertEqual(compressor.write(b |
|
1038 | self.assertEqual(compressor.write(b"foo"), 3) | |
1028 |
self.assertEqual(compressor.write(b |
|
1039 | self.assertEqual(compressor.write(b"barbiz"), 6) | |
1029 |
self.assertEqual(compressor.write(b |
|
1040 | self.assertEqual(compressor.write(b"x" * 8192), 8192) | |
1030 |
|
1041 | |||
1031 | def test_dictionary(self): |
|
1042 | def test_dictionary(self): | |
1032 | samples = [] |
|
1043 | samples = [] | |
1033 | for i in range(128): |
|
1044 | for i in range(128): | |
1034 |
samples.append(b |
|
1045 | samples.append(b"foo" * 64) | |
1035 |
samples.append(b |
|
1046 | samples.append(b"bar" * 64) | |
1036 |
samples.append(b |
|
1047 | samples.append(b"foobar" * 64) | |
1037 |
|
1048 | |||
1038 | d = zstd.train_dictionary(8192, samples) |
|
1049 | d = zstd.train_dictionary(8192, samples) | |
1039 |
|
1050 | |||
1040 | h = hashlib.sha1(d.as_bytes()).hexdigest() |
|
1051 | h = hashlib.sha1(d.as_bytes()).hexdigest() | |
1041 |
self.assertEqual(h, |
|
1052 | self.assertEqual(h, "7a2e59a876db958f74257141045af8f912e00d4e") | |
1042 |
|
1053 | |||
1043 | buffer = NonClosingBytesIO() |
|
1054 | buffer = NonClosingBytesIO() | |
1044 | cctx = zstd.ZstdCompressor(level=9, dict_data=d) |
|
1055 | cctx = zstd.ZstdCompressor(level=9, dict_data=d) | |
1045 | with cctx.stream_writer(buffer) as compressor: |
|
1056 | with cctx.stream_writer(buffer) as compressor: | |
1046 |
self.assertEqual(compressor.write(b |
|
1057 | self.assertEqual(compressor.write(b"foo"), 0) | |
1047 |
self.assertEqual(compressor.write(b |
|
1058 | self.assertEqual(compressor.write(b"bar"), 0) | |
1048 |
self.assertEqual(compressor.write(b |
|
1059 | self.assertEqual(compressor.write(b"foo" * 16384), 0) | |
1049 |
|
1060 | |||
1050 | compressed = buffer.getvalue() |
|
1061 | compressed = buffer.getvalue() | |
1051 |
|
1062 | |||
@@ -1056,14 +1067,15 b' class TestCompressor_stream_writer(unitt' | |||||
1056 | self.assertFalse(params.has_checksum) |
|
1067 | self.assertFalse(params.has_checksum) | |
1057 |
|
1068 | |||
1058 | h = hashlib.sha1(compressed).hexdigest() |
|
1069 | h = hashlib.sha1(compressed).hexdigest() | |
1059 |
self.assertEqual(h, |
|
1070 | self.assertEqual(h, "0a7c05635061f58039727cdbe76388c6f4cfef06") | |
1060 |
|
1071 | |||
1061 |
source = b |
|
1072 | source = b"foo" + b"bar" + (b"foo" * 16384) | |
1062 |
|
1073 | |||
1063 | dctx = zstd.ZstdDecompressor(dict_data=d) |
|
1074 | dctx = zstd.ZstdDecompressor(dict_data=d) | |
1064 |
|
1075 | |||
1065 | self.assertEqual(dctx.decompress(compressed, max_output_size=len(source)), |
|
1076 | self.assertEqual( | |
1066 | source) |
|
1077 | dctx.decompress(compressed, max_output_size=len(source)), source | |
|
1078 | ) | |||
1067 |
|
1079 | |||
1068 | def test_compression_params(self): |
|
1080 | def test_compression_params(self): | |
1069 | params = zstd.ZstdCompressionParameters( |
|
1081 | params = zstd.ZstdCompressionParameters( | |
@@ -1073,14 +1085,15 b' class TestCompressor_stream_writer(unitt' | |||||
1073 | min_match=5, |
|
1085 | min_match=5, | |
1074 | search_log=4, |
|
1086 | search_log=4, | |
1075 | target_length=10, |
|
1087 | target_length=10, | |
1076 |
strategy=zstd.STRATEGY_FAST |
|
1088 | strategy=zstd.STRATEGY_FAST, | |
|
1089 | ) | |||
1077 |
|
1090 | |||
1078 | buffer = NonClosingBytesIO() |
|
1091 | buffer = NonClosingBytesIO() | |
1079 | cctx = zstd.ZstdCompressor(compression_params=params) |
|
1092 | cctx = zstd.ZstdCompressor(compression_params=params) | |
1080 | with cctx.stream_writer(buffer) as compressor: |
|
1093 | with cctx.stream_writer(buffer) as compressor: | |
1081 |
self.assertEqual(compressor.write(b |
|
1094 | self.assertEqual(compressor.write(b"foo"), 0) | |
1082 |
self.assertEqual(compressor.write(b |
|
1095 | self.assertEqual(compressor.write(b"bar"), 0) | |
1083 |
self.assertEqual(compressor.write(b |
|
1096 | self.assertEqual(compressor.write(b"foobar" * 16384), 0) | |
1084 |
|
1097 | |||
1085 | compressed = buffer.getvalue() |
|
1098 | compressed = buffer.getvalue() | |
1086 |
|
1099 | |||
@@ -1091,18 +1104,18 b' class TestCompressor_stream_writer(unitt' | |||||
1091 | self.assertFalse(params.has_checksum) |
|
1104 | self.assertFalse(params.has_checksum) | |
1092 |
|
1105 | |||
1093 | h = hashlib.sha1(compressed).hexdigest() |
|
1106 | h = hashlib.sha1(compressed).hexdigest() | |
1094 |
self.assertEqual(h, |
|
1107 | self.assertEqual(h, "dd4bb7d37c1a0235b38a2f6b462814376843ef0b") | |
1095 |
|
1108 | |||
1096 | def test_write_checksum(self): |
|
1109 | def test_write_checksum(self): | |
1097 | no_checksum = NonClosingBytesIO() |
|
1110 | no_checksum = NonClosingBytesIO() | |
1098 | cctx = zstd.ZstdCompressor(level=1) |
|
1111 | cctx = zstd.ZstdCompressor(level=1) | |
1099 | with cctx.stream_writer(no_checksum) as compressor: |
|
1112 | with cctx.stream_writer(no_checksum) as compressor: | |
1100 |
self.assertEqual(compressor.write(b |
|
1113 | self.assertEqual(compressor.write(b"foobar"), 0) | |
1101 |
|
1114 | |||
1102 | with_checksum = NonClosingBytesIO() |
|
1115 | with_checksum = NonClosingBytesIO() | |
1103 | cctx = zstd.ZstdCompressor(level=1, write_checksum=True) |
|
1116 | cctx = zstd.ZstdCompressor(level=1, write_checksum=True) | |
1104 | with cctx.stream_writer(with_checksum) as compressor: |
|
1117 | with cctx.stream_writer(with_checksum) as compressor: | |
1105 |
self.assertEqual(compressor.write(b |
|
1118 | self.assertEqual(compressor.write(b"foobar"), 0) | |
1106 |
|
1119 | |||
1107 | no_params = zstd.get_frame_parameters(no_checksum.getvalue()) |
|
1120 | no_params = zstd.get_frame_parameters(no_checksum.getvalue()) | |
1108 | with_params = zstd.get_frame_parameters(with_checksum.getvalue()) |
|
1121 | with_params = zstd.get_frame_parameters(with_checksum.getvalue()) | |
@@ -1113,29 +1126,27 b' class TestCompressor_stream_writer(unitt' | |||||
1113 | self.assertFalse(no_params.has_checksum) |
|
1126 | self.assertFalse(no_params.has_checksum) | |
1114 | self.assertTrue(with_params.has_checksum) |
|
1127 | self.assertTrue(with_params.has_checksum) | |
1115 |
|
1128 | |||
1116 | self.assertEqual(len(with_checksum.getvalue()), |
|
1129 | self.assertEqual(len(with_checksum.getvalue()), len(no_checksum.getvalue()) + 4) | |
1117 | len(no_checksum.getvalue()) + 4) |
|
|||
1118 |
|
1130 | |||
1119 | def test_write_content_size(self): |
|
1131 | def test_write_content_size(self): | |
1120 | no_size = NonClosingBytesIO() |
|
1132 | no_size = NonClosingBytesIO() | |
1121 | cctx = zstd.ZstdCompressor(level=1, write_content_size=False) |
|
1133 | cctx = zstd.ZstdCompressor(level=1, write_content_size=False) | |
1122 | with cctx.stream_writer(no_size) as compressor: |
|
1134 | with cctx.stream_writer(no_size) as compressor: | |
1123 |
self.assertEqual(compressor.write(b |
|
1135 | self.assertEqual(compressor.write(b"foobar" * 256), 0) | |
1124 |
|
1136 | |||
1125 | with_size = NonClosingBytesIO() |
|
1137 | with_size = NonClosingBytesIO() | |
1126 | cctx = zstd.ZstdCompressor(level=1) |
|
1138 | cctx = zstd.ZstdCompressor(level=1) | |
1127 | with cctx.stream_writer(with_size) as compressor: |
|
1139 | with cctx.stream_writer(with_size) as compressor: | |
1128 |
self.assertEqual(compressor.write(b |
|
1140 | self.assertEqual(compressor.write(b"foobar" * 256), 0) | |
1129 |
|
1141 | |||
1130 | # Source size is not known in streaming mode, so header not |
|
1142 | # Source size is not known in streaming mode, so header not | |
1131 | # written. |
|
1143 | # written. | |
1132 | self.assertEqual(len(with_size.getvalue()), |
|
1144 | self.assertEqual(len(with_size.getvalue()), len(no_size.getvalue())) | |
1133 | len(no_size.getvalue())) |
|
|||
1134 |
|
1145 | |||
1135 | # Declaring size will write the header. |
|
1146 | # Declaring size will write the header. | |
1136 | with_size = NonClosingBytesIO() |
|
1147 | with_size = NonClosingBytesIO() | |
1137 |
with cctx.stream_writer(with_size, size=len(b |
|
1148 | with cctx.stream_writer(with_size, size=len(b"foobar" * 256)) as compressor: | |
1138 |
self.assertEqual(compressor.write(b |
|
1149 | self.assertEqual(compressor.write(b"foobar" * 256), 0) | |
1139 |
|
1150 | |||
1140 | no_params = zstd.get_frame_parameters(no_size.getvalue()) |
|
1151 | no_params = zstd.get_frame_parameters(no_size.getvalue()) | |
1141 | with_params = zstd.get_frame_parameters(with_size.getvalue()) |
|
1152 | with_params = zstd.get_frame_parameters(with_size.getvalue()) | |
@@ -1146,31 +1157,30 b' class TestCompressor_stream_writer(unitt' | |||||
1146 | self.assertFalse(no_params.has_checksum) |
|
1157 | self.assertFalse(no_params.has_checksum) | |
1147 | self.assertFalse(with_params.has_checksum) |
|
1158 | self.assertFalse(with_params.has_checksum) | |
1148 |
|
1159 | |||
1149 | self.assertEqual(len(with_size.getvalue()), |
|
1160 | self.assertEqual(len(with_size.getvalue()), len(no_size.getvalue()) + 1) | |
1150 | len(no_size.getvalue()) + 1) |
|
|||
1151 |
|
1161 | |||
1152 | def test_no_dict_id(self): |
|
1162 | def test_no_dict_id(self): | |
1153 | samples = [] |
|
1163 | samples = [] | |
1154 | for i in range(128): |
|
1164 | for i in range(128): | |
1155 |
samples.append(b |
|
1165 | samples.append(b"foo" * 64) | |
1156 |
samples.append(b |
|
1166 | samples.append(b"bar" * 64) | |
1157 |
samples.append(b |
|
1167 | samples.append(b"foobar" * 64) | |
1158 |
|
1168 | |||
1159 | d = zstd.train_dictionary(1024, samples) |
|
1169 | d = zstd.train_dictionary(1024, samples) | |
1160 |
|
1170 | |||
1161 | with_dict_id = NonClosingBytesIO() |
|
1171 | with_dict_id = NonClosingBytesIO() | |
1162 | cctx = zstd.ZstdCompressor(level=1, dict_data=d) |
|
1172 | cctx = zstd.ZstdCompressor(level=1, dict_data=d) | |
1163 | with cctx.stream_writer(with_dict_id) as compressor: |
|
1173 | with cctx.stream_writer(with_dict_id) as compressor: | |
1164 |
self.assertEqual(compressor.write(b |
|
1174 | self.assertEqual(compressor.write(b"foobarfoobar"), 0) | |
1165 |
|
1175 | |||
1166 |
self.assertEqual(with_dict_id.getvalue()[4:5], b |
|
1176 | self.assertEqual(with_dict_id.getvalue()[4:5], b"\x03") | |
1167 |
|
1177 | |||
1168 | cctx = zstd.ZstdCompressor(level=1, dict_data=d, write_dict_id=False) |
|
1178 | cctx = zstd.ZstdCompressor(level=1, dict_data=d, write_dict_id=False) | |
1169 | no_dict_id = NonClosingBytesIO() |
|
1179 | no_dict_id = NonClosingBytesIO() | |
1170 | with cctx.stream_writer(no_dict_id) as compressor: |
|
1180 | with cctx.stream_writer(no_dict_id) as compressor: | |
1171 |
self.assertEqual(compressor.write(b |
|
1181 | self.assertEqual(compressor.write(b"foobarfoobar"), 0) | |
1172 |
|
1182 | |||
1173 |
self.assertEqual(no_dict_id.getvalue()[4:5], b |
|
1183 | self.assertEqual(no_dict_id.getvalue()[4:5], b"\x00") | |
1174 |
|
1184 | |||
1175 | no_params = zstd.get_frame_parameters(no_dict_id.getvalue()) |
|
1185 | no_params = zstd.get_frame_parameters(no_dict_id.getvalue()) | |
1176 | with_params = zstd.get_frame_parameters(with_dict_id.getvalue()) |
|
1186 | with_params = zstd.get_frame_parameters(with_dict_id.getvalue()) | |
@@ -1181,14 +1191,13 b' class TestCompressor_stream_writer(unitt' | |||||
1181 | self.assertFalse(no_params.has_checksum) |
|
1191 | self.assertFalse(no_params.has_checksum) | |
1182 | self.assertFalse(with_params.has_checksum) |
|
1192 | self.assertFalse(with_params.has_checksum) | |
1183 |
|
1193 | |||
1184 | self.assertEqual(len(with_dict_id.getvalue()), |
|
1194 | self.assertEqual(len(with_dict_id.getvalue()), len(no_dict_id.getvalue()) + 4) | |
1185 | len(no_dict_id.getvalue()) + 4) |
|
|||
1186 |
|
1195 | |||
1187 | def test_memory_size(self): |
|
1196 | def test_memory_size(self): | |
1188 | cctx = zstd.ZstdCompressor(level=3) |
|
1197 | cctx = zstd.ZstdCompressor(level=3) | |
1189 | buffer = io.BytesIO() |
|
1198 | buffer = io.BytesIO() | |
1190 | with cctx.stream_writer(buffer) as compressor: |
|
1199 | with cctx.stream_writer(buffer) as compressor: | |
1191 |
compressor.write(b |
|
1200 | compressor.write(b"foo") | |
1192 | size = compressor.memory_size() |
|
1201 | size = compressor.memory_size() | |
1193 |
|
1202 | |||
1194 | self.assertGreater(size, 100000) |
|
1203 | self.assertGreater(size, 100000) | |
@@ -1197,9 +1206,9 b' class TestCompressor_stream_writer(unitt' | |||||
1197 | cctx = zstd.ZstdCompressor(level=3) |
|
1206 | cctx = zstd.ZstdCompressor(level=3) | |
1198 | dest = OpCountingBytesIO() |
|
1207 | dest = OpCountingBytesIO() | |
1199 | with cctx.stream_writer(dest, write_size=1) as compressor: |
|
1208 | with cctx.stream_writer(dest, write_size=1) as compressor: | |
1200 |
self.assertEqual(compressor.write(b |
|
1209 | self.assertEqual(compressor.write(b"foo"), 0) | |
1201 |
self.assertEqual(compressor.write(b |
|
1210 | self.assertEqual(compressor.write(b"bar"), 0) | |
1202 |
self.assertEqual(compressor.write(b |
|
1211 | self.assertEqual(compressor.write(b"foobar"), 0) | |
1203 |
|
1212 | |||
1204 | self.assertEqual(len(dest.getvalue()), dest._write_count) |
|
1213 | self.assertEqual(len(dest.getvalue()), dest._write_count) | |
1205 |
|
1214 | |||
@@ -1207,15 +1216,15 b' class TestCompressor_stream_writer(unitt' | |||||
1207 | cctx = zstd.ZstdCompressor(level=3) |
|
1216 | cctx = zstd.ZstdCompressor(level=3) | |
1208 | dest = OpCountingBytesIO() |
|
1217 | dest = OpCountingBytesIO() | |
1209 | with cctx.stream_writer(dest) as compressor: |
|
1218 | with cctx.stream_writer(dest) as compressor: | |
1210 |
self.assertEqual(compressor.write(b |
|
1219 | self.assertEqual(compressor.write(b"foo"), 0) | |
1211 | self.assertEqual(dest._write_count, 0) |
|
1220 | self.assertEqual(dest._write_count, 0) | |
1212 | self.assertEqual(compressor.flush(), 12) |
|
1221 | self.assertEqual(compressor.flush(), 12) | |
1213 | self.assertEqual(dest._write_count, 1) |
|
1222 | self.assertEqual(dest._write_count, 1) | |
1214 |
self.assertEqual(compressor.write(b |
|
1223 | self.assertEqual(compressor.write(b"bar"), 0) | |
1215 | self.assertEqual(dest._write_count, 1) |
|
1224 | self.assertEqual(dest._write_count, 1) | |
1216 | self.assertEqual(compressor.flush(), 6) |
|
1225 | self.assertEqual(compressor.flush(), 6) | |
1217 | self.assertEqual(dest._write_count, 2) |
|
1226 | self.assertEqual(dest._write_count, 2) | |
1218 |
self.assertEqual(compressor.write(b |
|
1227 | self.assertEqual(compressor.write(b"baz"), 0) | |
1219 |
|
1228 | |||
1220 | self.assertEqual(dest._write_count, 3) |
|
1229 | self.assertEqual(dest._write_count, 3) | |
1221 |
|
1230 | |||
@@ -1223,7 +1232,7 b' class TestCompressor_stream_writer(unitt' | |||||
1223 | cctx = zstd.ZstdCompressor(level=3, write_checksum=True) |
|
1232 | cctx = zstd.ZstdCompressor(level=3, write_checksum=True) | |
1224 | dest = OpCountingBytesIO() |
|
1233 | dest = OpCountingBytesIO() | |
1225 | with cctx.stream_writer(dest) as compressor: |
|
1234 | with cctx.stream_writer(dest) as compressor: | |
1226 |
self.assertEqual(compressor.write(b |
|
1235 | self.assertEqual(compressor.write(b"foobar" * 8192), 0) | |
1227 | count = dest._write_count |
|
1236 | count = dest._write_count | |
1228 | offset = dest.tell() |
|
1237 | offset = dest.tell() | |
1229 | self.assertEqual(compressor.flush(), 23) |
|
1238 | self.assertEqual(compressor.flush(), 23) | |
@@ -1238,41 +1247,43 b' class TestCompressor_stream_writer(unitt' | |||||
1238 | self.assertEqual(len(trailing), 7) |
|
1247 | self.assertEqual(len(trailing), 7) | |
1239 |
|
1248 | |||
1240 | header = trailing[0:3] |
|
1249 | header = trailing[0:3] | |
1241 |
self.assertEqual(header, b |
|
1250 | self.assertEqual(header, b"\x01\x00\x00") | |
1242 |
|
1251 | |||
1243 | def test_flush_frame(self): |
|
1252 | def test_flush_frame(self): | |
1244 | cctx = zstd.ZstdCompressor(level=3) |
|
1253 | cctx = zstd.ZstdCompressor(level=3) | |
1245 | dest = OpCountingBytesIO() |
|
1254 | dest = OpCountingBytesIO() | |
1246 |
|
1255 | |||
1247 | with cctx.stream_writer(dest) as compressor: |
|
1256 | with cctx.stream_writer(dest) as compressor: | |
1248 |
self.assertEqual(compressor.write(b |
|
1257 | self.assertEqual(compressor.write(b"foobar" * 8192), 0) | |
1249 | self.assertEqual(compressor.flush(zstd.FLUSH_FRAME), 23) |
|
1258 | self.assertEqual(compressor.flush(zstd.FLUSH_FRAME), 23) | |
1250 |
compressor.write(b |
|
1259 | compressor.write(b"biz" * 16384) | |
1251 |
|
1260 | |||
1252 |
self.assertEqual( |
|
1261 | self.assertEqual( | |
1253 | # Frame 1. |
|
1262 | dest.getvalue(), | |
1254 | b'\x28\xb5\x2f\xfd\x00\x58\x75\x00\x00\x30\x66\x6f\x6f' |
|
1263 | # Frame 1. | |
1255 | b'\x62\x61\x72\x01\x00\xf7\xbf\xe8\xa5\x08' |
|
1264 | b"\x28\xb5\x2f\xfd\x00\x58\x75\x00\x00\x30\x66\x6f\x6f" | |
1256 | # Frame 2. |
|
1265 | b"\x62\x61\x72\x01\x00\xf7\xbf\xe8\xa5\x08" | |
1257 | b'\x28\xb5\x2f\xfd\x00\x58\x5d\x00\x00\x18\x62\x69\x7a' |
|
1266 | # Frame 2. | |
1258 | b'\x01\x00\xfa\x3f\x75\x37\x04') |
|
1267 | b"\x28\xb5\x2f\xfd\x00\x58\x5d\x00\x00\x18\x62\x69\x7a" | |
|
1268 | b"\x01\x00\xfa\x3f\x75\x37\x04", | |||
|
1269 | ) | |||
1259 |
|
1270 | |||
1260 | def test_bad_flush_mode(self): |
|
1271 | def test_bad_flush_mode(self): | |
1261 | cctx = zstd.ZstdCompressor() |
|
1272 | cctx = zstd.ZstdCompressor() | |
1262 | dest = io.BytesIO() |
|
1273 | dest = io.BytesIO() | |
1263 | with cctx.stream_writer(dest) as compressor: |
|
1274 | with cctx.stream_writer(dest) as compressor: | |
1264 |
with self.assertRaisesRegex |
|
1275 | with self.assertRaisesRegex(ValueError, "unknown flush_mode: 42"): | |
1265 | compressor.flush(flush_mode=42) |
|
1276 | compressor.flush(flush_mode=42) | |
1266 |
|
1277 | |||
1267 | def test_multithreaded(self): |
|
1278 | def test_multithreaded(self): | |
1268 | dest = NonClosingBytesIO() |
|
1279 | dest = NonClosingBytesIO() | |
1269 | cctx = zstd.ZstdCompressor(threads=2) |
|
1280 | cctx = zstd.ZstdCompressor(threads=2) | |
1270 | with cctx.stream_writer(dest) as compressor: |
|
1281 | with cctx.stream_writer(dest) as compressor: | |
1271 |
compressor.write(b |
|
1282 | compressor.write(b"a" * 1048576) | |
1272 |
compressor.write(b |
|
1283 | compressor.write(b"b" * 1048576) | |
1273 |
compressor.write(b |
|
1284 | compressor.write(b"c" * 1048576) | |
1274 |
|
1285 | |||
1275 |
self.assertEqual(len(dest.getvalue()), |
|
1286 | self.assertEqual(len(dest.getvalue()), 111) | |
1276 |
|
1287 | |||
1277 | def test_tell(self): |
|
1288 | def test_tell(self): | |
1278 | dest = io.BytesIO() |
|
1289 | dest = io.BytesIO() | |
@@ -1281,7 +1292,7 b' class TestCompressor_stream_writer(unitt' | |||||
1281 | self.assertEqual(compressor.tell(), 0) |
|
1292 | self.assertEqual(compressor.tell(), 0) | |
1282 |
|
1293 | |||
1283 | for i in range(256): |
|
1294 | for i in range(256): | |
1284 |
compressor.write(b |
|
1295 | compressor.write(b"foo" * (i + 1)) | |
1285 | self.assertEqual(compressor.tell(), dest.tell()) |
|
1296 | self.assertEqual(compressor.tell(), dest.tell()) | |
1286 |
|
1297 | |||
1287 | def test_bad_size(self): |
|
1298 | def test_bad_size(self): | |
@@ -1289,9 +1300,9 b' class TestCompressor_stream_writer(unitt' | |||||
1289 |
|
1300 | |||
1290 | dest = io.BytesIO() |
|
1301 | dest = io.BytesIO() | |
1291 |
|
1302 | |||
1292 |
with self.assertRaisesRegex |
|
1303 | with self.assertRaisesRegex(zstd.ZstdError, "Src size is incorrect"): | |
1293 | with cctx.stream_writer(dest, size=2) as compressor: |
|
1304 | with cctx.stream_writer(dest, size=2) as compressor: | |
1294 |
compressor.write(b |
|
1305 | compressor.write(b"foo") | |
1295 |
|
1306 | |||
1296 | # Test another operation. |
|
1307 | # Test another operation. | |
1297 | with cctx.stream_writer(dest, size=42): |
|
1308 | with cctx.stream_writer(dest, size=42): | |
@@ -1301,20 +1312,20 b' class TestCompressor_stream_writer(unitt' | |||||
1301 | dest = NonClosingBytesIO() |
|
1312 | dest = NonClosingBytesIO() | |
1302 | cctx = zstd.ZstdCompressor() |
|
1313 | cctx = zstd.ZstdCompressor() | |
1303 | with cctx.stream_writer(dest) as compressor: |
|
1314 | with cctx.stream_writer(dest) as compressor: | |
1304 |
with tarfile.open( |
|
1315 | with tarfile.open("tf", mode="w|", fileobj=compressor) as tf: | |
1305 |
tf.add(__file__, |
|
1316 | tf.add(__file__, "test_compressor.py") | |
1306 |
|
1317 | |||
1307 | dest = io.BytesIO(dest.getvalue()) |
|
1318 | dest = io.BytesIO(dest.getvalue()) | |
1308 |
|
1319 | |||
1309 | dctx = zstd.ZstdDecompressor() |
|
1320 | dctx = zstd.ZstdDecompressor() | |
1310 | with dctx.stream_reader(dest) as reader: |
|
1321 | with dctx.stream_reader(dest) as reader: | |
1311 |
with tarfile.open(mode= |
|
1322 | with tarfile.open(mode="r|", fileobj=reader) as tf: | |
1312 | for member in tf: |
|
1323 | for member in tf: | |
1313 |
self.assertEqual(member.name, |
|
1324 | self.assertEqual(member.name, "test_compressor.py") | |
1314 |
|
1325 | |||
1315 |
|
1326 | |||
1316 | @make_cffi |
|
1327 | @make_cffi | |
1317 |
class TestCompressor_read_to_iter( |
|
1328 | class TestCompressor_read_to_iter(TestCase): | |
1318 | def test_type_validation(self): |
|
1329 | def test_type_validation(self): | |
1319 | cctx = zstd.ZstdCompressor() |
|
1330 | cctx = zstd.ZstdCompressor() | |
1320 |
|
1331 | |||
@@ -1323,10 +1334,10 b' class TestCompressor_read_to_iter(unitte' | |||||
1323 | pass |
|
1334 | pass | |
1324 |
|
1335 | |||
1325 | # Buffer protocol works. |
|
1336 | # Buffer protocol works. | |
1326 |
for chunk in cctx.read_to_iter(b |
|
1337 | for chunk in cctx.read_to_iter(b"foobar"): | |
1327 | pass |
|
1338 | pass | |
1328 |
|
1339 | |||
1329 |
with self.assertRaisesRegex |
|
1340 | with self.assertRaisesRegex(ValueError, "must pass an object with a read"): | |
1330 | for chunk in cctx.read_to_iter(True): |
|
1341 | for chunk in cctx.read_to_iter(True): | |
1331 | pass |
|
1342 | pass | |
1332 |
|
1343 | |||
@@ -1337,22 +1348,22 b' class TestCompressor_read_to_iter(unitte' | |||||
1337 | it = cctx.read_to_iter(source) |
|
1348 | it = cctx.read_to_iter(source) | |
1338 | chunks = list(it) |
|
1349 | chunks = list(it) | |
1339 | self.assertEqual(len(chunks), 1) |
|
1350 | self.assertEqual(len(chunks), 1) | |
1340 |
compressed = b |
|
1351 | compressed = b"".join(chunks) | |
1341 |
self.assertEqual(compressed, b |
|
1352 | self.assertEqual(compressed, b"\x28\xb5\x2f\xfd\x00\x48\x01\x00\x00") | |
1342 |
|
1353 | |||
1343 | # And again with the buffer protocol. |
|
1354 | # And again with the buffer protocol. | |
1344 |
it = cctx.read_to_iter(b |
|
1355 | it = cctx.read_to_iter(b"") | |
1345 | chunks = list(it) |
|
1356 | chunks = list(it) | |
1346 | self.assertEqual(len(chunks), 1) |
|
1357 | self.assertEqual(len(chunks), 1) | |
1347 |
compressed2 = b |
|
1358 | compressed2 = b"".join(chunks) | |
1348 | self.assertEqual(compressed2, compressed) |
|
1359 | self.assertEqual(compressed2, compressed) | |
1349 |
|
1360 | |||
1350 | def test_read_large(self): |
|
1361 | def test_read_large(self): | |
1351 | cctx = zstd.ZstdCompressor(level=1, write_content_size=False) |
|
1362 | cctx = zstd.ZstdCompressor(level=1, write_content_size=False) | |
1352 |
|
1363 | |||
1353 | source = io.BytesIO() |
|
1364 | source = io.BytesIO() | |
1354 |
source.write(b |
|
1365 | source.write(b"f" * zstd.COMPRESSION_RECOMMENDED_INPUT_SIZE) | |
1355 |
source.write(b |
|
1366 | source.write(b"o") | |
1356 | source.seek(0) |
|
1367 | source.seek(0) | |
1357 |
|
1368 | |||
1358 | # Creating an iterator should not perform any compression until |
|
1369 | # Creating an iterator should not perform any compression until | |
@@ -1380,9 +1391,9 b' class TestCompressor_read_to_iter(unitte' | |||||
1380 | next(it) |
|
1391 | next(it) | |
1381 |
|
1392 | |||
1382 | # We should get the same output as the one-shot compression mechanism. |
|
1393 | # We should get the same output as the one-shot compression mechanism. | |
1383 |
self.assertEqual(b |
|
1394 | self.assertEqual(b"".join(chunks), cctx.compress(source.getvalue())) | |
1384 |
|
1395 | |||
1385 |
params = zstd.get_frame_parameters(b |
|
1396 | params = zstd.get_frame_parameters(b"".join(chunks)) | |
1386 | self.assertEqual(params.content_size, zstd.CONTENTSIZE_UNKNOWN) |
|
1397 | self.assertEqual(params.content_size, zstd.CONTENTSIZE_UNKNOWN) | |
1387 | self.assertEqual(params.window_size, 262144) |
|
1398 | self.assertEqual(params.window_size, 262144) | |
1388 | self.assertEqual(params.dict_id, 0) |
|
1399 | self.assertEqual(params.dict_id, 0) | |
@@ -1393,16 +1404,16 b' class TestCompressor_read_to_iter(unitte' | |||||
1393 | chunks = list(it) |
|
1404 | chunks = list(it) | |
1394 | self.assertEqual(len(chunks), 2) |
|
1405 | self.assertEqual(len(chunks), 2) | |
1395 |
|
1406 | |||
1396 |
params = zstd.get_frame_parameters(b |
|
1407 | params = zstd.get_frame_parameters(b"".join(chunks)) | |
1397 | self.assertEqual(params.content_size, zstd.CONTENTSIZE_UNKNOWN) |
|
1408 | self.assertEqual(params.content_size, zstd.CONTENTSIZE_UNKNOWN) | |
1398 | #self.assertEqual(params.window_size, 262144) |
|
1409 | # self.assertEqual(params.window_size, 262144) | |
1399 | self.assertEqual(params.dict_id, 0) |
|
1410 | self.assertEqual(params.dict_id, 0) | |
1400 | self.assertFalse(params.has_checksum) |
|
1411 | self.assertFalse(params.has_checksum) | |
1401 |
|
1412 | |||
1402 |
self.assertEqual(b |
|
1413 | self.assertEqual(b"".join(chunks), cctx.compress(source.getvalue())) | |
1403 |
|
1414 | |||
1404 | def test_read_write_size(self): |
|
1415 | def test_read_write_size(self): | |
1405 |
source = OpCountingBytesIO(b |
|
1416 | source = OpCountingBytesIO(b"foobarfoobar") | |
1406 | cctx = zstd.ZstdCompressor(level=3) |
|
1417 | cctx = zstd.ZstdCompressor(level=3) | |
1407 | for chunk in cctx.read_to_iter(source, read_size=1, write_size=1): |
|
1418 | for chunk in cctx.read_to_iter(source, read_size=1, write_size=1): | |
1408 | self.assertEqual(len(chunk), 1) |
|
1419 | self.assertEqual(len(chunk), 1) | |
@@ -1411,42 +1422,42 b' class TestCompressor_read_to_iter(unitte' | |||||
1411 |
|
1422 | |||
1412 | def test_multithreaded(self): |
|
1423 | def test_multithreaded(self): | |
1413 | source = io.BytesIO() |
|
1424 | source = io.BytesIO() | |
1414 |
source.write(b |
|
1425 | source.write(b"a" * 1048576) | |
1415 |
source.write(b |
|
1426 | source.write(b"b" * 1048576) | |
1416 |
source.write(b |
|
1427 | source.write(b"c" * 1048576) | |
1417 | source.seek(0) |
|
1428 | source.seek(0) | |
1418 |
|
1429 | |||
1419 | cctx = zstd.ZstdCompressor(threads=2) |
|
1430 | cctx = zstd.ZstdCompressor(threads=2) | |
1420 |
|
1431 | |||
1421 |
compressed = b |
|
1432 | compressed = b"".join(cctx.read_to_iter(source)) | |
1422 |
self.assertEqual(len(compressed), |
|
1433 | self.assertEqual(len(compressed), 111) | |
1423 |
|
1434 | |||
1424 | def test_bad_size(self): |
|
1435 | def test_bad_size(self): | |
1425 | cctx = zstd.ZstdCompressor() |
|
1436 | cctx = zstd.ZstdCompressor() | |
1426 |
|
1437 | |||
1427 |
source = io.BytesIO(b |
|
1438 | source = io.BytesIO(b"a" * 42) | |
1428 |
|
1439 | |||
1429 |
with self.assertRaisesRegex |
|
1440 | with self.assertRaisesRegex(zstd.ZstdError, "Src size is incorrect"): | |
1430 |
b |
|
1441 | b"".join(cctx.read_to_iter(source, size=2)) | |
1431 |
|
1442 | |||
1432 | # Test another operation on errored compressor. |
|
1443 | # Test another operation on errored compressor. | |
1433 |
b |
|
1444 | b"".join(cctx.read_to_iter(source)) | |
1434 |
|
1445 | |||
1435 |
|
1446 | |||
1436 | @make_cffi |
|
1447 | @make_cffi | |
1437 |
class TestCompressor_chunker( |
|
1448 | class TestCompressor_chunker(TestCase): | |
1438 | def test_empty(self): |
|
1449 | def test_empty(self): | |
1439 | cctx = zstd.ZstdCompressor(write_content_size=False) |
|
1450 | cctx = zstd.ZstdCompressor(write_content_size=False) | |
1440 | chunker = cctx.chunker() |
|
1451 | chunker = cctx.chunker() | |
1441 |
|
1452 | |||
1442 |
it = chunker.compress(b |
|
1453 | it = chunker.compress(b"") | |
1443 |
|
1454 | |||
1444 | with self.assertRaises(StopIteration): |
|
1455 | with self.assertRaises(StopIteration): | |
1445 | next(it) |
|
1456 | next(it) | |
1446 |
|
1457 | |||
1447 | it = chunker.finish() |
|
1458 | it = chunker.finish() | |
1448 |
|
1459 | |||
1449 |
self.assertEqual(next(it), b |
|
1460 | self.assertEqual(next(it), b"\x28\xb5\x2f\xfd\x00\x58\x01\x00\x00") | |
1450 |
|
1461 | |||
1451 | with self.assertRaises(StopIteration): |
|
1462 | with self.assertRaises(StopIteration): | |
1452 | next(it) |
|
1463 | next(it) | |
@@ -1455,21 +1466,23 b' class TestCompressor_chunker(unittest.Te' | |||||
1455 | cctx = zstd.ZstdCompressor() |
|
1466 | cctx = zstd.ZstdCompressor() | |
1456 | chunker = cctx.chunker() |
|
1467 | chunker = cctx.chunker() | |
1457 |
|
1468 | |||
1458 |
it = chunker.compress(b |
|
1469 | it = chunker.compress(b"foobar") | |
1459 |
|
1470 | |||
1460 | with self.assertRaises(StopIteration): |
|
1471 | with self.assertRaises(StopIteration): | |
1461 | next(it) |
|
1472 | next(it) | |
1462 |
|
1473 | |||
1463 |
it = chunker.compress(b |
|
1474 | it = chunker.compress(b"baz" * 30) | |
1464 |
|
1475 | |||
1465 | with self.assertRaises(StopIteration): |
|
1476 | with self.assertRaises(StopIteration): | |
1466 | next(it) |
|
1477 | next(it) | |
1467 |
|
1478 | |||
1468 | it = chunker.finish() |
|
1479 | it = chunker.finish() | |
1469 |
|
1480 | |||
1470 |
self.assertEqual( |
|
1481 | self.assertEqual( | |
1471 | b'\x28\xb5\x2f\xfd\x00\x58\x7d\x00\x00\x48\x66\x6f' |
|
1482 | next(it), | |
1472 | b'\x6f\x62\x61\x72\x62\x61\x7a\x01\x00\xe4\xe4\x8e') |
|
1483 | b"\x28\xb5\x2f\xfd\x00\x58\x7d\x00\x00\x48\x66\x6f" | |
|
1484 | b"\x6f\x62\x61\x72\x62\x61\x7a\x01\x00\xe4\xe4\x8e", | |||
|
1485 | ) | |||
1473 |
|
1486 | |||
1474 | with self.assertRaises(StopIteration): |
|
1487 | with self.assertRaises(StopIteration): | |
1475 | next(it) |
|
1488 | next(it) | |
@@ -1478,57 +1491,60 b' class TestCompressor_chunker(unittest.Te' | |||||
1478 | cctx = zstd.ZstdCompressor() |
|
1491 | cctx = zstd.ZstdCompressor() | |
1479 | chunker = cctx.chunker(size=1024) |
|
1492 | chunker = cctx.chunker(size=1024) | |
1480 |
|
1493 | |||
1481 |
it = chunker.compress(b |
|
1494 | it = chunker.compress(b"x" * 1000) | |
1482 |
|
1495 | |||
1483 | with self.assertRaises(StopIteration): |
|
1496 | with self.assertRaises(StopIteration): | |
1484 | next(it) |
|
1497 | next(it) | |
1485 |
|
1498 | |||
1486 |
it = chunker.compress(b |
|
1499 | it = chunker.compress(b"y" * 24) | |
1487 |
|
1500 | |||
1488 | with self.assertRaises(StopIteration): |
|
1501 | with self.assertRaises(StopIteration): | |
1489 | next(it) |
|
1502 | next(it) | |
1490 |
|
1503 | |||
1491 | chunks = list(chunker.finish()) |
|
1504 | chunks = list(chunker.finish()) | |
1492 |
|
1505 | |||
1493 |
self.assertEqual( |
|
1506 | self.assertEqual( | |
1494 | b'\x28\xb5\x2f\xfd\x60\x00\x03\x65\x00\x00\x18\x78\x78\x79\x02\x00' |
|
1507 | chunks, | |
1495 | b'\xa0\x16\xe3\x2b\x80\x05' |
|
1508 | [ | |
1496 | ]) |
|
1509 | b"\x28\xb5\x2f\xfd\x60\x00\x03\x65\x00\x00\x18\x78\x78\x79\x02\x00" | |
|
1510 | b"\xa0\x16\xe3\x2b\x80\x05" | |||
|
1511 | ], | |||
|
1512 | ) | |||
1497 |
|
1513 | |||
1498 | dctx = zstd.ZstdDecompressor() |
|
1514 | dctx = zstd.ZstdDecompressor() | |
1499 |
|
1515 | |||
1500 |
self.assertEqual(dctx.decompress(b |
|
1516 | self.assertEqual(dctx.decompress(b"".join(chunks)), (b"x" * 1000) + (b"y" * 24)) | |
1501 | (b'x' * 1000) + (b'y' * 24)) |
|
|||
1502 |
|
1517 | |||
1503 | def test_small_chunk_size(self): |
|
1518 | def test_small_chunk_size(self): | |
1504 | cctx = zstd.ZstdCompressor() |
|
1519 | cctx = zstd.ZstdCompressor() | |
1505 | chunker = cctx.chunker(chunk_size=1) |
|
1520 | chunker = cctx.chunker(chunk_size=1) | |
1506 |
|
1521 | |||
1507 |
chunks = list(chunker.compress(b |
|
1522 | chunks = list(chunker.compress(b"foo" * 1024)) | |
1508 | self.assertEqual(chunks, []) |
|
1523 | self.assertEqual(chunks, []) | |
1509 |
|
1524 | |||
1510 | chunks = list(chunker.finish()) |
|
1525 | chunks = list(chunker.finish()) | |
1511 | self.assertTrue(all(len(chunk) == 1 for chunk in chunks)) |
|
1526 | self.assertTrue(all(len(chunk) == 1 for chunk in chunks)) | |
1512 |
|
1527 | |||
1513 | self.assertEqual( |
|
1528 | self.assertEqual( | |
1514 |
b |
|
1529 | b"".join(chunks), | |
1515 |
b |
|
1530 | b"\x28\xb5\x2f\xfd\x00\x58\x55\x00\x00\x18\x66\x6f\x6f\x01\x00" | |
1516 |
b |
|
1531 | b"\xfa\xd3\x77\x43", | |
|
1532 | ) | |||
1517 |
|
1533 | |||
1518 | dctx = zstd.ZstdDecompressor() |
|
1534 | dctx = zstd.ZstdDecompressor() | |
1519 |
self.assertEqual( |
|
1535 | self.assertEqual( | |
1520 | max_output_size=10000), |
|
1536 | dctx.decompress(b"".join(chunks), max_output_size=10000), b"foo" * 1024 | |
1521 | b'foo' * 1024) |
|
1537 | ) | |
1522 |
|
1538 | |||
1523 | def test_input_types(self): |
|
1539 | def test_input_types(self): | |
1524 | cctx = zstd.ZstdCompressor() |
|
1540 | cctx = zstd.ZstdCompressor() | |
1525 |
|
1541 | |||
1526 | mutable_array = bytearray(3) |
|
1542 | mutable_array = bytearray(3) | |
1527 |
mutable_array[:] = b |
|
1543 | mutable_array[:] = b"foo" | |
1528 |
|
1544 | |||
1529 | sources = [ |
|
1545 | sources = [ | |
1530 |
memoryview(b |
|
1546 | memoryview(b"foo"), | |
1531 |
bytearray(b |
|
1547 | bytearray(b"foo"), | |
1532 | mutable_array, |
|
1548 | mutable_array, | |
1533 | ] |
|
1549 | ] | |
1534 |
|
1550 | |||
@@ -1536,28 +1552,32 b' class TestCompressor_chunker(unittest.Te' | |||||
1536 | chunker = cctx.chunker() |
|
1552 | chunker = cctx.chunker() | |
1537 |
|
1553 | |||
1538 | self.assertEqual(list(chunker.compress(source)), []) |
|
1554 | self.assertEqual(list(chunker.compress(source)), []) | |
1539 |
self.assertEqual( |
|
1555 | self.assertEqual( | |
1540 | b'\x28\xb5\x2f\xfd\x00\x58\x19\x00\x00\x66\x6f\x6f' |
|
1556 | list(chunker.finish()), | |
1541 | ]) |
|
1557 | [b"\x28\xb5\x2f\xfd\x00\x58\x19\x00\x00\x66\x6f\x6f"], | |
|
1558 | ) | |||
1542 |
|
1559 | |||
1543 | def test_flush(self): |
|
1560 | def test_flush(self): | |
1544 | cctx = zstd.ZstdCompressor() |
|
1561 | cctx = zstd.ZstdCompressor() | |
1545 | chunker = cctx.chunker() |
|
1562 | chunker = cctx.chunker() | |
1546 |
|
1563 | |||
1547 |
self.assertEqual(list(chunker.compress(b |
|
1564 | self.assertEqual(list(chunker.compress(b"foo" * 1024)), []) | |
1548 |
self.assertEqual(list(chunker.compress(b |
|
1565 | self.assertEqual(list(chunker.compress(b"bar" * 1024)), []) | |
1549 |
|
1566 | |||
1550 | chunks1 = list(chunker.flush()) |
|
1567 | chunks1 = list(chunker.flush()) | |
1551 |
|
1568 | |||
1552 |
self.assertEqual( |
|
1569 | self.assertEqual( | |
1553 | b'\x28\xb5\x2f\xfd\x00\x58\x8c\x00\x00\x30\x66\x6f\x6f\x62\x61\x72' |
|
1570 | chunks1, | |
1554 | b'\x02\x00\xfa\x03\xfe\xd0\x9f\xbe\x1b\x02' |
|
1571 | [ | |
1555 | ]) |
|
1572 | b"\x28\xb5\x2f\xfd\x00\x58\x8c\x00\x00\x30\x66\x6f\x6f\x62\x61\x72" | |
|
1573 | b"\x02\x00\xfa\x03\xfe\xd0\x9f\xbe\x1b\x02" | |||
|
1574 | ], | |||
|
1575 | ) | |||
1556 |
|
1576 | |||
1557 | self.assertEqual(list(chunker.flush()), []) |
|
1577 | self.assertEqual(list(chunker.flush()), []) | |
1558 | self.assertEqual(list(chunker.flush()), []) |
|
1578 | self.assertEqual(list(chunker.flush()), []) | |
1559 |
|
1579 | |||
1560 |
self.assertEqual(list(chunker.compress(b |
|
1580 | self.assertEqual(list(chunker.compress(b"baz" * 1024)), []) | |
1561 |
|
1581 | |||
1562 | chunks2 = list(chunker.flush()) |
|
1582 | chunks2 = list(chunker.flush()) | |
1563 | self.assertEqual(len(chunks2), 1) |
|
1583 | self.assertEqual(len(chunks2), 1) | |
@@ -1567,53 +1587,56 b' class TestCompressor_chunker(unittest.Te' | |||||
1567 |
|
1587 | |||
1568 | dctx = zstd.ZstdDecompressor() |
|
1588 | dctx = zstd.ZstdDecompressor() | |
1569 |
|
1589 | |||
1570 | self.assertEqual(dctx.decompress(b''.join(chunks1 + chunks2 + chunks3), |
|
1590 | self.assertEqual( | |
1571 | max_output_size=10000), |
|
1591 | dctx.decompress( | |
1572 | (b'foo' * 1024) + (b'bar' * 1024) + (b'baz' * 1024)) |
|
1592 | b"".join(chunks1 + chunks2 + chunks3), max_output_size=10000 | |
|
1593 | ), | |||
|
1594 | (b"foo" * 1024) + (b"bar" * 1024) + (b"baz" * 1024), | |||
|
1595 | ) | |||
1573 |
|
1596 | |||
1574 | def test_compress_after_finish(self): |
|
1597 | def test_compress_after_finish(self): | |
1575 | cctx = zstd.ZstdCompressor() |
|
1598 | cctx = zstd.ZstdCompressor() | |
1576 | chunker = cctx.chunker() |
|
1599 | chunker = cctx.chunker() | |
1577 |
|
1600 | |||
1578 |
list(chunker.compress(b |
|
1601 | list(chunker.compress(b"foo")) | |
1579 | list(chunker.finish()) |
|
1602 | list(chunker.finish()) | |
1580 |
|
1603 | |||
1581 |
with self.assertRaisesRegex |
|
1604 | with self.assertRaisesRegex( | |
1582 | zstd.ZstdError, |
|
1605 | zstd.ZstdError, r"cannot call compress\(\) after compression finished" | |
1583 | r'cannot call compress\(\) after compression finished'): |
|
1606 | ): | |
1584 |
list(chunker.compress(b |
|
1607 | list(chunker.compress(b"foo")) | |
1585 |
|
1608 | |||
1586 | def test_flush_after_finish(self): |
|
1609 | def test_flush_after_finish(self): | |
1587 | cctx = zstd.ZstdCompressor() |
|
1610 | cctx = zstd.ZstdCompressor() | |
1588 | chunker = cctx.chunker() |
|
1611 | chunker = cctx.chunker() | |
1589 |
|
1612 | |||
1590 |
list(chunker.compress(b |
|
1613 | list(chunker.compress(b"foo")) | |
1591 | list(chunker.finish()) |
|
1614 | list(chunker.finish()) | |
1592 |
|
1615 | |||
1593 |
with self.assertRaisesRegex |
|
1616 | with self.assertRaisesRegex( | |
1594 | zstd.ZstdError, |
|
1617 | zstd.ZstdError, r"cannot call flush\(\) after compression finished" | |
1595 | r'cannot call flush\(\) after compression finished'): |
|
1618 | ): | |
1596 | list(chunker.flush()) |
|
1619 | list(chunker.flush()) | |
1597 |
|
1620 | |||
1598 | def test_finish_after_finish(self): |
|
1621 | def test_finish_after_finish(self): | |
1599 | cctx = zstd.ZstdCompressor() |
|
1622 | cctx = zstd.ZstdCompressor() | |
1600 | chunker = cctx.chunker() |
|
1623 | chunker = cctx.chunker() | |
1601 |
|
1624 | |||
1602 |
list(chunker.compress(b |
|
1625 | list(chunker.compress(b"foo")) | |
1603 | list(chunker.finish()) |
|
1626 | list(chunker.finish()) | |
1604 |
|
1627 | |||
1605 |
with self.assertRaisesRegex |
|
1628 | with self.assertRaisesRegex( | |
1606 | zstd.ZstdError, |
|
1629 | zstd.ZstdError, r"cannot call finish\(\) after compression finished" | |
1607 | r'cannot call finish\(\) after compression finished'): |
|
1630 | ): | |
1608 | list(chunker.finish()) |
|
1631 | list(chunker.finish()) | |
1609 |
|
1632 | |||
1610 |
|
1633 | |||
1611 |
class TestCompressor_multi_compress_to_buffer( |
|
1634 | class TestCompressor_multi_compress_to_buffer(TestCase): | |
1612 | def test_invalid_inputs(self): |
|
1635 | def test_invalid_inputs(self): | |
1613 | cctx = zstd.ZstdCompressor() |
|
1636 | cctx = zstd.ZstdCompressor() | |
1614 |
|
1637 | |||
1615 |
if not hasattr(cctx, |
|
1638 | if not hasattr(cctx, "multi_compress_to_buffer"): | |
1616 |
self.skipTest( |
|
1639 | self.skipTest("multi_compress_to_buffer not available") | |
1617 |
|
1640 | |||
1618 | with self.assertRaises(TypeError): |
|
1641 | with self.assertRaises(TypeError): | |
1619 | cctx.multi_compress_to_buffer(True) |
|
1642 | cctx.multi_compress_to_buffer(True) | |
@@ -1621,28 +1644,28 b' class TestCompressor_multi_compress_to_b' | |||||
1621 | with self.assertRaises(TypeError): |
|
1644 | with self.assertRaises(TypeError): | |
1622 | cctx.multi_compress_to_buffer((1, 2)) |
|
1645 | cctx.multi_compress_to_buffer((1, 2)) | |
1623 |
|
1646 | |||
1624 |
with self.assertRaisesRegex |
|
1647 | with self.assertRaisesRegex(TypeError, "item 0 not a bytes like object"): | |
1625 |
cctx.multi_compress_to_buffer([u |
|
1648 | cctx.multi_compress_to_buffer([u"foo"]) | |
1626 |
|
1649 | |||
1627 | def test_empty_input(self): |
|
1650 | def test_empty_input(self): | |
1628 | cctx = zstd.ZstdCompressor() |
|
1651 | cctx = zstd.ZstdCompressor() | |
1629 |
|
1652 | |||
1630 |
if not hasattr(cctx, |
|
1653 | if not hasattr(cctx, "multi_compress_to_buffer"): | |
1631 |
self.skipTest( |
|
1654 | self.skipTest("multi_compress_to_buffer not available") | |
1632 |
|
1655 | |||
1633 |
with self.assertRaisesRegex |
|
1656 | with self.assertRaisesRegex(ValueError, "no source elements found"): | |
1634 | cctx.multi_compress_to_buffer([]) |
|
1657 | cctx.multi_compress_to_buffer([]) | |
1635 |
|
1658 | |||
1636 |
with self.assertRaisesRegex |
|
1659 | with self.assertRaisesRegex(ValueError, "source elements are empty"): | |
1637 |
cctx.multi_compress_to_buffer([b |
|
1660 | cctx.multi_compress_to_buffer([b"", b"", b""]) | |
1638 |
|
1661 | |||
1639 | def test_list_input(self): |
|
1662 | def test_list_input(self): | |
1640 | cctx = zstd.ZstdCompressor(write_checksum=True) |
|
1663 | cctx = zstd.ZstdCompressor(write_checksum=True) | |
1641 |
|
1664 | |||
1642 |
if not hasattr(cctx, |
|
1665 | if not hasattr(cctx, "multi_compress_to_buffer"): | |
1643 |
self.skipTest( |
|
1666 | self.skipTest("multi_compress_to_buffer not available") | |
1644 |
|
1667 | |||
1645 |
original = [b |
|
1668 | original = [b"foo" * 12, b"bar" * 6] | |
1646 | frames = [cctx.compress(c) for c in original] |
|
1669 | frames = [cctx.compress(c) for c in original] | |
1647 | b = cctx.multi_compress_to_buffer(original) |
|
1670 | b = cctx.multi_compress_to_buffer(original) | |
1648 |
|
1671 | |||
@@ -1657,15 +1680,16 b' class TestCompressor_multi_compress_to_b' | |||||
1657 | def test_buffer_with_segments_input(self): |
|
1680 | def test_buffer_with_segments_input(self): | |
1658 | cctx = zstd.ZstdCompressor(write_checksum=True) |
|
1681 | cctx = zstd.ZstdCompressor(write_checksum=True) | |
1659 |
|
1682 | |||
1660 |
if not hasattr(cctx, |
|
1683 | if not hasattr(cctx, "multi_compress_to_buffer"): | |
1661 |
self.skipTest( |
|
1684 | self.skipTest("multi_compress_to_buffer not available") | |
1662 |
|
1685 | |||
1663 |
original = [b |
|
1686 | original = [b"foo" * 4, b"bar" * 6] | |
1664 | frames = [cctx.compress(c) for c in original] |
|
1687 | frames = [cctx.compress(c) for c in original] | |
1665 |
|
1688 | |||
1666 |
offsets = struct.pack( |
|
1689 | offsets = struct.pack( | |
1667 |
|
|
1690 | "=QQQQ", 0, len(original[0]), len(original[0]), len(original[1]) | |
1668 | segments = zstd.BufferWithSegments(b''.join(original), offsets) |
|
1691 | ) | |
|
1692 | segments = zstd.BufferWithSegments(b"".join(original), offsets) | |||
1669 |
|
1693 | |||
1670 | result = cctx.multi_compress_to_buffer(segments) |
|
1694 | result = cctx.multi_compress_to_buffer(segments) | |
1671 |
|
1695 | |||
@@ -1678,28 +1702,39 b' class TestCompressor_multi_compress_to_b' | |||||
1678 | def test_buffer_with_segments_collection_input(self): |
|
1702 | def test_buffer_with_segments_collection_input(self): | |
1679 | cctx = zstd.ZstdCompressor(write_checksum=True) |
|
1703 | cctx = zstd.ZstdCompressor(write_checksum=True) | |
1680 |
|
1704 | |||
1681 |
if not hasattr(cctx, |
|
1705 | if not hasattr(cctx, "multi_compress_to_buffer"): | |
1682 |
self.skipTest( |
|
1706 | self.skipTest("multi_compress_to_buffer not available") | |
1683 |
|
1707 | |||
1684 | original = [ |
|
1708 | original = [ | |
1685 |
b |
|
1709 | b"foo1", | |
1686 |
b |
|
1710 | b"foo2" * 2, | |
1687 |
b |
|
1711 | b"foo3" * 3, | |
1688 |
b |
|
1712 | b"foo4" * 4, | |
1689 |
b |
|
1713 | b"foo5" * 5, | |
1690 | ] |
|
1714 | ] | |
1691 |
|
1715 | |||
1692 | frames = [cctx.compress(c) for c in original] |
|
1716 | frames = [cctx.compress(c) for c in original] | |
1693 |
|
1717 | |||
1694 |
b = b |
|
1718 | b = b"".join([original[0], original[1]]) | |
1695 |
b1 = zstd.BufferWithSegments( |
|
1719 | b1 = zstd.BufferWithSegments( | |
1696 | 0, len(original[0]), |
|
1720 | b, | |
1697 | len(original[0]), len(original[1]))) |
|
1721 | struct.pack( | |
1698 |
|
|
1722 | "=QQQQ", 0, len(original[0]), len(original[0]), len(original[1]) | |
1699 | b2 = zstd.BufferWithSegments(b, struct.pack('=QQQQQQ', |
|
1723 | ), | |
1700 | 0, len(original[2]), |
|
1724 | ) | |
1701 | len(original[2]), len(original[3]), |
|
1725 | b = b"".join([original[2], original[3], original[4]]) | |
1702 | len(original[2]) + len(original[3]), len(original[4]))) |
|
1726 | b2 = zstd.BufferWithSegments( | |
|
1727 | b, | |||
|
1728 | struct.pack( | |||
|
1729 | "=QQQQQQ", | |||
|
1730 | 0, | |||
|
1731 | len(original[2]), | |||
|
1732 | len(original[2]), | |||
|
1733 | len(original[3]), | |||
|
1734 | len(original[2]) + len(original[3]), | |||
|
1735 | len(original[4]), | |||
|
1736 | ), | |||
|
1737 | ) | |||
1703 |
|
1738 | |||
1704 | c = zstd.BufferWithSegmentsCollection(b1, b2) |
|
1739 | c = zstd.BufferWithSegmentsCollection(b1, b2) | |
1705 |
|
1740 | |||
@@ -1714,16 +1749,16 b' class TestCompressor_multi_compress_to_b' | |||||
1714 | # threads argument will cause multi-threaded ZSTD APIs to be used, which will |
|
1749 | # threads argument will cause multi-threaded ZSTD APIs to be used, which will | |
1715 | # make output different. |
|
1750 | # make output different. | |
1716 | refcctx = zstd.ZstdCompressor(write_checksum=True) |
|
1751 | refcctx = zstd.ZstdCompressor(write_checksum=True) | |
1717 |
reference = [refcctx.compress(b |
|
1752 | reference = [refcctx.compress(b"x" * 64), refcctx.compress(b"y" * 64)] | |
1718 |
|
1753 | |||
1719 | cctx = zstd.ZstdCompressor(write_checksum=True) |
|
1754 | cctx = zstd.ZstdCompressor(write_checksum=True) | |
1720 |
|
1755 | |||
1721 |
if not hasattr(cctx, |
|
1756 | if not hasattr(cctx, "multi_compress_to_buffer"): | |
1722 |
self.skipTest( |
|
1757 | self.skipTest("multi_compress_to_buffer not available") | |
1723 |
|
1758 | |||
1724 | frames = [] |
|
1759 | frames = [] | |
1725 |
frames.extend(b |
|
1760 | frames.extend(b"x" * 64 for i in range(256)) | |
1726 |
frames.extend(b |
|
1761 | frames.extend(b"y" * 64 for i in range(256)) | |
1727 |
|
1762 | |||
1728 | result = cctx.multi_compress_to_buffer(frames, threads=-1) |
|
1763 | result = cctx.multi_compress_to_buffer(frames, threads=-1) | |
1729 |
|
1764 |
This diff has been collapsed as it changes many lines, (631 lines changed) Show them Hide them | |||||
@@ -6,28 +6,31 b' try:' | |||||
6 | import hypothesis |
|
6 | import hypothesis | |
7 | import hypothesis.strategies as strategies |
|
7 | import hypothesis.strategies as strategies | |
8 | except ImportError: |
|
8 | except ImportError: | |
9 |
raise unittest.SkipTest( |
|
9 | raise unittest.SkipTest("hypothesis not available") | |
10 |
|
10 | |||
11 | import zstandard as zstd |
|
11 | import zstandard as zstd | |
12 |
|
12 | |||
13 |
from . |
|
13 | from .common import ( | |
14 | make_cffi, |
|
14 | make_cffi, | |
15 | NonClosingBytesIO, |
|
15 | NonClosingBytesIO, | |
16 | random_input_data, |
|
16 | random_input_data, | |
|
17 | TestCase, | |||
17 | ) |
|
18 | ) | |
18 |
|
19 | |||
19 |
|
20 | |||
20 |
@unittest.skipUnless( |
|
21 | @unittest.skipUnless("ZSTD_SLOW_TESTS" in os.environ, "ZSTD_SLOW_TESTS not set") | |
21 | @make_cffi |
|
22 | @make_cffi | |
22 |
class TestCompressor_stream_reader_fuzzing( |
|
23 | class TestCompressor_stream_reader_fuzzing(TestCase): | |
23 | @hypothesis.settings( |
|
24 | @hypothesis.settings( | |
24 |
suppress_health_check=[hypothesis.HealthCheck.large_base_example] |
|
25 | suppress_health_check=[hypothesis.HealthCheck.large_base_example] | |
25 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
26 | ) | |
26 | level=strategies.integers(min_value=1, max_value=5), |
|
27 | @hypothesis.given( | |
27 | source_read_size=strategies.integers(1, 16384), |
|
28 | original=strategies.sampled_from(random_input_data()), | |
28 | read_size=strategies.integers(-1, zstd.COMPRESSION_RECOMMENDED_OUTPUT_SIZE)) |
|
29 | level=strategies.integers(min_value=1, max_value=5), | |
29 | def test_stream_source_read(self, original, level, source_read_size, |
|
30 | source_read_size=strategies.integers(1, 16384), | |
30 | read_size): |
|
31 | read_size=strategies.integers(-1, zstd.COMPRESSION_RECOMMENDED_OUTPUT_SIZE), | |
|
32 | ) | |||
|
33 | def test_stream_source_read(self, original, level, source_read_size, read_size): | |||
31 | if read_size == 0: |
|
34 | if read_size == 0: | |
32 | read_size = -1 |
|
35 | read_size = -1 | |
33 |
|
36 | |||
@@ -35,8 +38,9 b' class TestCompressor_stream_reader_fuzzi' | |||||
35 | ref_frame = refctx.compress(original) |
|
38 | ref_frame = refctx.compress(original) | |
36 |
|
39 | |||
37 | cctx = zstd.ZstdCompressor(level=level) |
|
40 | cctx = zstd.ZstdCompressor(level=level) | |
38 |
with cctx.stream_reader( |
|
41 | with cctx.stream_reader( | |
39 | read_size=source_read_size) as reader: |
|
42 | io.BytesIO(original), size=len(original), read_size=source_read_size | |
|
43 | ) as reader: | |||
40 | chunks = [] |
|
44 | chunks = [] | |
41 | while True: |
|
45 | while True: | |
42 | chunk = reader.read(read_size) |
|
46 | chunk = reader.read(read_size) | |
@@ -45,16 +49,18 b' class TestCompressor_stream_reader_fuzzi' | |||||
45 |
|
49 | |||
46 | chunks.append(chunk) |
|
50 | chunks.append(chunk) | |
47 |
|
51 | |||
48 |
self.assertEqual(b |
|
52 | self.assertEqual(b"".join(chunks), ref_frame) | |
49 |
|
53 | |||
50 | @hypothesis.settings( |
|
54 | @hypothesis.settings( | |
51 |
suppress_health_check=[hypothesis.HealthCheck.large_base_example] |
|
55 | suppress_health_check=[hypothesis.HealthCheck.large_base_example] | |
52 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
56 | ) | |
53 | level=strategies.integers(min_value=1, max_value=5), |
|
57 | @hypothesis.given( | |
54 | source_read_size=strategies.integers(1, 16384), |
|
58 | original=strategies.sampled_from(random_input_data()), | |
55 | read_size=strategies.integers(-1, zstd.COMPRESSION_RECOMMENDED_OUTPUT_SIZE)) |
|
59 | level=strategies.integers(min_value=1, max_value=5), | |
56 | def test_buffer_source_read(self, original, level, source_read_size, |
|
60 | source_read_size=strategies.integers(1, 16384), | |
57 | read_size): |
|
61 | read_size=strategies.integers(-1, zstd.COMPRESSION_RECOMMENDED_OUTPUT_SIZE), | |
|
62 | ) | |||
|
63 | def test_buffer_source_read(self, original, level, source_read_size, read_size): | |||
58 | if read_size == 0: |
|
64 | if read_size == 0: | |
59 | read_size = -1 |
|
65 | read_size = -1 | |
60 |
|
66 | |||
@@ -62,8 +68,9 b' class TestCompressor_stream_reader_fuzzi' | |||||
62 | ref_frame = refctx.compress(original) |
|
68 | ref_frame = refctx.compress(original) | |
63 |
|
69 | |||
64 | cctx = zstd.ZstdCompressor(level=level) |
|
70 | cctx = zstd.ZstdCompressor(level=level) | |
65 |
with cctx.stream_reader( |
|
71 | with cctx.stream_reader( | |
66 | read_size=source_read_size) as reader: |
|
72 | original, size=len(original), read_size=source_read_size | |
|
73 | ) as reader: | |||
67 | chunks = [] |
|
74 | chunks = [] | |
68 | while True: |
|
75 | while True: | |
69 | chunk = reader.read(read_size) |
|
76 | chunk = reader.read(read_size) | |
@@ -72,22 +79,30 b' class TestCompressor_stream_reader_fuzzi' | |||||
72 |
|
79 | |||
73 | chunks.append(chunk) |
|
80 | chunks.append(chunk) | |
74 |
|
81 | |||
75 |
self.assertEqual(b |
|
82 | self.assertEqual(b"".join(chunks), ref_frame) | |
76 |
|
83 | |||
77 | @hypothesis.settings( |
|
84 | @hypothesis.settings( | |
78 | suppress_health_check=[hypothesis.HealthCheck.large_base_example]) |
|
85 | suppress_health_check=[ | |
79 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
86 | hypothesis.HealthCheck.large_base_example, | |
80 | level=strategies.integers(min_value=1, max_value=5), |
|
87 | hypothesis.HealthCheck.too_slow, | |
81 | source_read_size=strategies.integers(1, 16384), |
|
88 | ] | |
82 | read_sizes=strategies.data()) |
|
89 | ) | |
83 | def test_stream_source_read_variance(self, original, level, source_read_size, |
|
90 | @hypothesis.given( | |
84 | read_sizes): |
|
91 | original=strategies.sampled_from(random_input_data()), | |
|
92 | level=strategies.integers(min_value=1, max_value=5), | |||
|
93 | source_read_size=strategies.integers(1, 16384), | |||
|
94 | read_sizes=strategies.data(), | |||
|
95 | ) | |||
|
96 | def test_stream_source_read_variance( | |||
|
97 | self, original, level, source_read_size, read_sizes | |||
|
98 | ): | |||
85 | refctx = zstd.ZstdCompressor(level=level) |
|
99 | refctx = zstd.ZstdCompressor(level=level) | |
86 | ref_frame = refctx.compress(original) |
|
100 | ref_frame = refctx.compress(original) | |
87 |
|
101 | |||
88 | cctx = zstd.ZstdCompressor(level=level) |
|
102 | cctx = zstd.ZstdCompressor(level=level) | |
89 |
with cctx.stream_reader( |
|
103 | with cctx.stream_reader( | |
90 | read_size=source_read_size) as reader: |
|
104 | io.BytesIO(original), size=len(original), read_size=source_read_size | |
|
105 | ) as reader: | |||
91 | chunks = [] |
|
106 | chunks = [] | |
92 | while True: |
|
107 | while True: | |
93 | read_size = read_sizes.draw(strategies.integers(-1, 16384)) |
|
108 | read_size = read_sizes.draw(strategies.integers(-1, 16384)) | |
@@ -97,23 +112,31 b' class TestCompressor_stream_reader_fuzzi' | |||||
97 |
|
112 | |||
98 | chunks.append(chunk) |
|
113 | chunks.append(chunk) | |
99 |
|
114 | |||
100 |
self.assertEqual(b |
|
115 | self.assertEqual(b"".join(chunks), ref_frame) | |
101 |
|
116 | |||
102 | @hypothesis.settings( |
|
117 | @hypothesis.settings( | |
103 | suppress_health_check=[hypothesis.HealthCheck.large_base_example]) |
|
118 | suppress_health_check=[ | |
104 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
119 | hypothesis.HealthCheck.large_base_example, | |
105 | level=strategies.integers(min_value=1, max_value=5), |
|
120 | hypothesis.HealthCheck.too_slow, | |
106 | source_read_size=strategies.integers(1, 16384), |
|
121 | ] | |
107 | read_sizes=strategies.data()) |
|
122 | ) | |
108 | def test_buffer_source_read_variance(self, original, level, source_read_size, |
|
123 | @hypothesis.given( | |
109 | read_sizes): |
|
124 | original=strategies.sampled_from(random_input_data()), | |
|
125 | level=strategies.integers(min_value=1, max_value=5), | |||
|
126 | source_read_size=strategies.integers(1, 16384), | |||
|
127 | read_sizes=strategies.data(), | |||
|
128 | ) | |||
|
129 | def test_buffer_source_read_variance( | |||
|
130 | self, original, level, source_read_size, read_sizes | |||
|
131 | ): | |||
110 |
|
132 | |||
111 | refctx = zstd.ZstdCompressor(level=level) |
|
133 | refctx = zstd.ZstdCompressor(level=level) | |
112 | ref_frame = refctx.compress(original) |
|
134 | ref_frame = refctx.compress(original) | |
113 |
|
135 | |||
114 | cctx = zstd.ZstdCompressor(level=level) |
|
136 | cctx = zstd.ZstdCompressor(level=level) | |
115 |
with cctx.stream_reader( |
|
137 | with cctx.stream_reader( | |
116 | read_size=source_read_size) as reader: |
|
138 | original, size=len(original), read_size=source_read_size | |
|
139 | ) as reader: | |||
117 | chunks = [] |
|
140 | chunks = [] | |
118 | while True: |
|
141 | while True: | |
119 | read_size = read_sizes.draw(strategies.integers(-1, 16384)) |
|
142 | read_size = read_sizes.draw(strategies.integers(-1, 16384)) | |
@@ -123,22 +146,25 b' class TestCompressor_stream_reader_fuzzi' | |||||
123 |
|
146 | |||
124 | chunks.append(chunk) |
|
147 | chunks.append(chunk) | |
125 |
|
148 | |||
126 |
self.assertEqual(b |
|
149 | self.assertEqual(b"".join(chunks), ref_frame) | |
127 |
|
150 | |||
128 | @hypothesis.settings( |
|
151 | @hypothesis.settings( | |
129 |
suppress_health_check=[hypothesis.HealthCheck.large_base_example] |
|
152 | suppress_health_check=[hypothesis.HealthCheck.large_base_example] | |
130 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
153 | ) | |
131 | level=strategies.integers(min_value=1, max_value=5), |
|
154 | @hypothesis.given( | |
132 | source_read_size=strategies.integers(1, 16384), |
|
155 | original=strategies.sampled_from(random_input_data()), | |
133 | read_size=strategies.integers(1, zstd.COMPRESSION_RECOMMENDED_OUTPUT_SIZE)) |
|
156 | level=strategies.integers(min_value=1, max_value=5), | |
134 | def test_stream_source_readinto(self, original, level, |
|
157 | source_read_size=strategies.integers(1, 16384), | |
135 | source_read_size, read_size): |
|
158 | read_size=strategies.integers(1, zstd.COMPRESSION_RECOMMENDED_OUTPUT_SIZE), | |
|
159 | ) | |||
|
160 | def test_stream_source_readinto(self, original, level, source_read_size, read_size): | |||
136 | refctx = zstd.ZstdCompressor(level=level) |
|
161 | refctx = zstd.ZstdCompressor(level=level) | |
137 | ref_frame = refctx.compress(original) |
|
162 | ref_frame = refctx.compress(original) | |
138 |
|
163 | |||
139 | cctx = zstd.ZstdCompressor(level=level) |
|
164 | cctx = zstd.ZstdCompressor(level=level) | |
140 |
with cctx.stream_reader( |
|
165 | with cctx.stream_reader( | |
141 | read_size=source_read_size) as reader: |
|
166 | io.BytesIO(original), size=len(original), read_size=source_read_size | |
|
167 | ) as reader: | |||
142 | chunks = [] |
|
168 | chunks = [] | |
143 | while True: |
|
169 | while True: | |
144 | b = bytearray(read_size) |
|
170 | b = bytearray(read_size) | |
@@ -149,23 +175,26 b' class TestCompressor_stream_reader_fuzzi' | |||||
149 |
|
175 | |||
150 | chunks.append(bytes(b[0:count])) |
|
176 | chunks.append(bytes(b[0:count])) | |
151 |
|
177 | |||
152 |
self.assertEqual(b |
|
178 | self.assertEqual(b"".join(chunks), ref_frame) | |
153 |
|
179 | |||
154 | @hypothesis.settings( |
|
180 | @hypothesis.settings( | |
155 |
suppress_health_check=[hypothesis.HealthCheck.large_base_example] |
|
181 | suppress_health_check=[hypothesis.HealthCheck.large_base_example] | |
156 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
182 | ) | |
157 | level=strategies.integers(min_value=1, max_value=5), |
|
183 | @hypothesis.given( | |
158 | source_read_size=strategies.integers(1, 16384), |
|
184 | original=strategies.sampled_from(random_input_data()), | |
159 | read_size=strategies.integers(1, zstd.COMPRESSION_RECOMMENDED_OUTPUT_SIZE)) |
|
185 | level=strategies.integers(min_value=1, max_value=5), | |
160 | def test_buffer_source_readinto(self, original, level, |
|
186 | source_read_size=strategies.integers(1, 16384), | |
161 | source_read_size, read_size): |
|
187 | read_size=strategies.integers(1, zstd.COMPRESSION_RECOMMENDED_OUTPUT_SIZE), | |
|
188 | ) | |||
|
189 | def test_buffer_source_readinto(self, original, level, source_read_size, read_size): | |||
162 |
|
190 | |||
163 | refctx = zstd.ZstdCompressor(level=level) |
|
191 | refctx = zstd.ZstdCompressor(level=level) | |
164 | ref_frame = refctx.compress(original) |
|
192 | ref_frame = refctx.compress(original) | |
165 |
|
193 | |||
166 | cctx = zstd.ZstdCompressor(level=level) |
|
194 | cctx = zstd.ZstdCompressor(level=level) | |
167 |
with cctx.stream_reader( |
|
195 | with cctx.stream_reader( | |
168 | read_size=source_read_size) as reader: |
|
196 | original, size=len(original), read_size=source_read_size | |
|
197 | ) as reader: | |||
169 | chunks = [] |
|
198 | chunks = [] | |
170 | while True: |
|
199 | while True: | |
171 | b = bytearray(read_size) |
|
200 | b = bytearray(read_size) | |
@@ -176,22 +205,30 b' class TestCompressor_stream_reader_fuzzi' | |||||
176 |
|
205 | |||
177 | chunks.append(bytes(b[0:count])) |
|
206 | chunks.append(bytes(b[0:count])) | |
178 |
|
207 | |||
179 |
self.assertEqual(b |
|
208 | self.assertEqual(b"".join(chunks), ref_frame) | |
180 |
|
209 | |||
181 | @hypothesis.settings( |
|
210 | @hypothesis.settings( | |
182 | suppress_health_check=[hypothesis.HealthCheck.large_base_example]) |
|
211 | suppress_health_check=[ | |
183 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
212 | hypothesis.HealthCheck.large_base_example, | |
184 | level=strategies.integers(min_value=1, max_value=5), |
|
213 | hypothesis.HealthCheck.too_slow, | |
185 | source_read_size=strategies.integers(1, 16384), |
|
214 | ] | |
186 | read_sizes=strategies.data()) |
|
215 | ) | |
187 | def test_stream_source_readinto_variance(self, original, level, |
|
216 | @hypothesis.given( | |
188 | source_read_size, read_sizes): |
|
217 | original=strategies.sampled_from(random_input_data()), | |
|
218 | level=strategies.integers(min_value=1, max_value=5), | |||
|
219 | source_read_size=strategies.integers(1, 16384), | |||
|
220 | read_sizes=strategies.data(), | |||
|
221 | ) | |||
|
222 | def test_stream_source_readinto_variance( | |||
|
223 | self, original, level, source_read_size, read_sizes | |||
|
224 | ): | |||
189 | refctx = zstd.ZstdCompressor(level=level) |
|
225 | refctx = zstd.ZstdCompressor(level=level) | |
190 | ref_frame = refctx.compress(original) |
|
226 | ref_frame = refctx.compress(original) | |
191 |
|
227 | |||
192 | cctx = zstd.ZstdCompressor(level=level) |
|
228 | cctx = zstd.ZstdCompressor(level=level) | |
193 |
with cctx.stream_reader( |
|
229 | with cctx.stream_reader( | |
194 | read_size=source_read_size) as reader: |
|
230 | io.BytesIO(original), size=len(original), read_size=source_read_size | |
|
231 | ) as reader: | |||
195 | chunks = [] |
|
232 | chunks = [] | |
196 | while True: |
|
233 | while True: | |
197 | read_size = read_sizes.draw(strategies.integers(1, 16384)) |
|
234 | read_size = read_sizes.draw(strategies.integers(1, 16384)) | |
@@ -203,23 +240,31 b' class TestCompressor_stream_reader_fuzzi' | |||||
203 |
|
240 | |||
204 | chunks.append(bytes(b[0:count])) |
|
241 | chunks.append(bytes(b[0:count])) | |
205 |
|
242 | |||
206 |
self.assertEqual(b |
|
243 | self.assertEqual(b"".join(chunks), ref_frame) | |
207 |
|
244 | |||
208 | @hypothesis.settings( |
|
245 | @hypothesis.settings( | |
209 | suppress_health_check=[hypothesis.HealthCheck.large_base_example]) |
|
246 | suppress_health_check=[ | |
210 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
247 | hypothesis.HealthCheck.large_base_example, | |
211 | level=strategies.integers(min_value=1, max_value=5), |
|
248 | hypothesis.HealthCheck.too_slow, | |
212 | source_read_size=strategies.integers(1, 16384), |
|
249 | ] | |
213 | read_sizes=strategies.data()) |
|
250 | ) | |
214 | def test_buffer_source_readinto_variance(self, original, level, |
|
251 | @hypothesis.given( | |
215 | source_read_size, read_sizes): |
|
252 | original=strategies.sampled_from(random_input_data()), | |
|
253 | level=strategies.integers(min_value=1, max_value=5), | |||
|
254 | source_read_size=strategies.integers(1, 16384), | |||
|
255 | read_sizes=strategies.data(), | |||
|
256 | ) | |||
|
257 | def test_buffer_source_readinto_variance( | |||
|
258 | self, original, level, source_read_size, read_sizes | |||
|
259 | ): | |||
216 |
|
260 | |||
217 | refctx = zstd.ZstdCompressor(level=level) |
|
261 | refctx = zstd.ZstdCompressor(level=level) | |
218 | ref_frame = refctx.compress(original) |
|
262 | ref_frame = refctx.compress(original) | |
219 |
|
263 | |||
220 | cctx = zstd.ZstdCompressor(level=level) |
|
264 | cctx = zstd.ZstdCompressor(level=level) | |
221 |
with cctx.stream_reader( |
|
265 | with cctx.stream_reader( | |
222 | read_size=source_read_size) as reader: |
|
266 | original, size=len(original), read_size=source_read_size | |
|
267 | ) as reader: | |||
223 | chunks = [] |
|
268 | chunks = [] | |
224 | while True: |
|
269 | while True: | |
225 | read_size = read_sizes.draw(strategies.integers(1, 16384)) |
|
270 | read_size = read_sizes.draw(strategies.integers(1, 16384)) | |
@@ -231,16 +276,18 b' class TestCompressor_stream_reader_fuzzi' | |||||
231 |
|
276 | |||
232 | chunks.append(bytes(b[0:count])) |
|
277 | chunks.append(bytes(b[0:count])) | |
233 |
|
278 | |||
234 |
self.assertEqual(b |
|
279 | self.assertEqual(b"".join(chunks), ref_frame) | |
235 |
|
280 | |||
236 | @hypothesis.settings( |
|
281 | @hypothesis.settings( | |
237 |
suppress_health_check=[hypothesis.HealthCheck.large_base_example] |
|
282 | suppress_health_check=[hypothesis.HealthCheck.large_base_example] | |
238 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
283 | ) | |
239 | level=strategies.integers(min_value=1, max_value=5), |
|
284 | @hypothesis.given( | |
240 | source_read_size=strategies.integers(1, 16384), |
|
285 | original=strategies.sampled_from(random_input_data()), | |
241 | read_size=strategies.integers(-1, zstd.COMPRESSION_RECOMMENDED_OUTPUT_SIZE)) |
|
286 | level=strategies.integers(min_value=1, max_value=5), | |
242 | def test_stream_source_read1(self, original, level, source_read_size, |
|
287 | source_read_size=strategies.integers(1, 16384), | |
243 | read_size): |
|
288 | read_size=strategies.integers(-1, zstd.COMPRESSION_RECOMMENDED_OUTPUT_SIZE), | |
|
289 | ) | |||
|
290 | def test_stream_source_read1(self, original, level, source_read_size, read_size): | |||
244 | if read_size == 0: |
|
291 | if read_size == 0: | |
245 | read_size = -1 |
|
292 | read_size = -1 | |
246 |
|
293 | |||
@@ -248,8 +295,9 b' class TestCompressor_stream_reader_fuzzi' | |||||
248 | ref_frame = refctx.compress(original) |
|
295 | ref_frame = refctx.compress(original) | |
249 |
|
296 | |||
250 | cctx = zstd.ZstdCompressor(level=level) |
|
297 | cctx = zstd.ZstdCompressor(level=level) | |
251 |
with cctx.stream_reader( |
|
298 | with cctx.stream_reader( | |
252 | read_size=source_read_size) as reader: |
|
299 | io.BytesIO(original), size=len(original), read_size=source_read_size | |
|
300 | ) as reader: | |||
253 | chunks = [] |
|
301 | chunks = [] | |
254 | while True: |
|
302 | while True: | |
255 | chunk = reader.read1(read_size) |
|
303 | chunk = reader.read1(read_size) | |
@@ -258,16 +306,18 b' class TestCompressor_stream_reader_fuzzi' | |||||
258 |
|
306 | |||
259 | chunks.append(chunk) |
|
307 | chunks.append(chunk) | |
260 |
|
308 | |||
261 |
self.assertEqual(b |
|
309 | self.assertEqual(b"".join(chunks), ref_frame) | |
262 |
|
310 | |||
263 | @hypothesis.settings( |
|
311 | @hypothesis.settings( | |
264 |
suppress_health_check=[hypothesis.HealthCheck.large_base_example] |
|
312 | suppress_health_check=[hypothesis.HealthCheck.large_base_example] | |
265 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
313 | ) | |
266 | level=strategies.integers(min_value=1, max_value=5), |
|
314 | @hypothesis.given( | |
267 | source_read_size=strategies.integers(1, 16384), |
|
315 | original=strategies.sampled_from(random_input_data()), | |
268 | read_size=strategies.integers(-1, zstd.COMPRESSION_RECOMMENDED_OUTPUT_SIZE)) |
|
316 | level=strategies.integers(min_value=1, max_value=5), | |
269 | def test_buffer_source_read1(self, original, level, source_read_size, |
|
317 | source_read_size=strategies.integers(1, 16384), | |
270 | read_size): |
|
318 | read_size=strategies.integers(-1, zstd.COMPRESSION_RECOMMENDED_OUTPUT_SIZE), | |
|
319 | ) | |||
|
320 | def test_buffer_source_read1(self, original, level, source_read_size, read_size): | |||
271 | if read_size == 0: |
|
321 | if read_size == 0: | |
272 | read_size = -1 |
|
322 | read_size = -1 | |
273 |
|
323 | |||
@@ -275,8 +325,9 b' class TestCompressor_stream_reader_fuzzi' | |||||
275 | ref_frame = refctx.compress(original) |
|
325 | ref_frame = refctx.compress(original) | |
276 |
|
326 | |||
277 | cctx = zstd.ZstdCompressor(level=level) |
|
327 | cctx = zstd.ZstdCompressor(level=level) | |
278 |
with cctx.stream_reader( |
|
328 | with cctx.stream_reader( | |
279 | read_size=source_read_size) as reader: |
|
329 | original, size=len(original), read_size=source_read_size | |
|
330 | ) as reader: | |||
280 | chunks = [] |
|
331 | chunks = [] | |
281 | while True: |
|
332 | while True: | |
282 | chunk = reader.read1(read_size) |
|
333 | chunk = reader.read1(read_size) | |
@@ -285,22 +336,30 b' class TestCompressor_stream_reader_fuzzi' | |||||
285 |
|
336 | |||
286 | chunks.append(chunk) |
|
337 | chunks.append(chunk) | |
287 |
|
338 | |||
288 |
self.assertEqual(b |
|
339 | self.assertEqual(b"".join(chunks), ref_frame) | |
289 |
|
340 | |||
290 | @hypothesis.settings( |
|
341 | @hypothesis.settings( | |
291 | suppress_health_check=[hypothesis.HealthCheck.large_base_example]) |
|
342 | suppress_health_check=[ | |
292 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
343 | hypothesis.HealthCheck.large_base_example, | |
293 | level=strategies.integers(min_value=1, max_value=5), |
|
344 | hypothesis.HealthCheck.too_slow, | |
294 | source_read_size=strategies.integers(1, 16384), |
|
345 | ] | |
295 | read_sizes=strategies.data()) |
|
346 | ) | |
296 | def test_stream_source_read1_variance(self, original, level, source_read_size, |
|
347 | @hypothesis.given( | |
297 | read_sizes): |
|
348 | original=strategies.sampled_from(random_input_data()), | |
|
349 | level=strategies.integers(min_value=1, max_value=5), | |||
|
350 | source_read_size=strategies.integers(1, 16384), | |||
|
351 | read_sizes=strategies.data(), | |||
|
352 | ) | |||
|
353 | def test_stream_source_read1_variance( | |||
|
354 | self, original, level, source_read_size, read_sizes | |||
|
355 | ): | |||
298 | refctx = zstd.ZstdCompressor(level=level) |
|
356 | refctx = zstd.ZstdCompressor(level=level) | |
299 | ref_frame = refctx.compress(original) |
|
357 | ref_frame = refctx.compress(original) | |
300 |
|
358 | |||
301 | cctx = zstd.ZstdCompressor(level=level) |
|
359 | cctx = zstd.ZstdCompressor(level=level) | |
302 |
with cctx.stream_reader( |
|
360 | with cctx.stream_reader( | |
303 | read_size=source_read_size) as reader: |
|
361 | io.BytesIO(original), size=len(original), read_size=source_read_size | |
|
362 | ) as reader: | |||
304 | chunks = [] |
|
363 | chunks = [] | |
305 | while True: |
|
364 | while True: | |
306 | read_size = read_sizes.draw(strategies.integers(-1, 16384)) |
|
365 | read_size = read_sizes.draw(strategies.integers(-1, 16384)) | |
@@ -310,23 +369,31 b' class TestCompressor_stream_reader_fuzzi' | |||||
310 |
|
369 | |||
311 | chunks.append(chunk) |
|
370 | chunks.append(chunk) | |
312 |
|
371 | |||
313 |
self.assertEqual(b |
|
372 | self.assertEqual(b"".join(chunks), ref_frame) | |
314 |
|
373 | |||
315 | @hypothesis.settings( |
|
374 | @hypothesis.settings( | |
316 | suppress_health_check=[hypothesis.HealthCheck.large_base_example]) |
|
375 | suppress_health_check=[ | |
317 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
376 | hypothesis.HealthCheck.large_base_example, | |
318 | level=strategies.integers(min_value=1, max_value=5), |
|
377 | hypothesis.HealthCheck.too_slow, | |
319 | source_read_size=strategies.integers(1, 16384), |
|
378 | ] | |
320 | read_sizes=strategies.data()) |
|
379 | ) | |
321 | def test_buffer_source_read1_variance(self, original, level, source_read_size, |
|
380 | @hypothesis.given( | |
322 | read_sizes): |
|
381 | original=strategies.sampled_from(random_input_data()), | |
|
382 | level=strategies.integers(min_value=1, max_value=5), | |||
|
383 | source_read_size=strategies.integers(1, 16384), | |||
|
384 | read_sizes=strategies.data(), | |||
|
385 | ) | |||
|
386 | def test_buffer_source_read1_variance( | |||
|
387 | self, original, level, source_read_size, read_sizes | |||
|
388 | ): | |||
323 |
|
389 | |||
324 | refctx = zstd.ZstdCompressor(level=level) |
|
390 | refctx = zstd.ZstdCompressor(level=level) | |
325 | ref_frame = refctx.compress(original) |
|
391 | ref_frame = refctx.compress(original) | |
326 |
|
392 | |||
327 | cctx = zstd.ZstdCompressor(level=level) |
|
393 | cctx = zstd.ZstdCompressor(level=level) | |
328 |
with cctx.stream_reader( |
|
394 | with cctx.stream_reader( | |
329 | read_size=source_read_size) as reader: |
|
395 | original, size=len(original), read_size=source_read_size | |
|
396 | ) as reader: | |||
330 | chunks = [] |
|
397 | chunks = [] | |
331 | while True: |
|
398 | while True: | |
332 | read_size = read_sizes.draw(strategies.integers(-1, 16384)) |
|
399 | read_size = read_sizes.draw(strategies.integers(-1, 16384)) | |
@@ -336,17 +403,20 b' class TestCompressor_stream_reader_fuzzi' | |||||
336 |
|
403 | |||
337 | chunks.append(chunk) |
|
404 | chunks.append(chunk) | |
338 |
|
405 | |||
339 |
self.assertEqual(b |
|
406 | self.assertEqual(b"".join(chunks), ref_frame) | |
340 |
|
||||
341 |
|
407 | |||
342 | @hypothesis.settings( |
|
408 | @hypothesis.settings( | |
343 |
suppress_health_check=[hypothesis.HealthCheck.large_base_example] |
|
409 | suppress_health_check=[hypothesis.HealthCheck.large_base_example] | |
344 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
410 | ) | |
345 | level=strategies.integers(min_value=1, max_value=5), |
|
411 | @hypothesis.given( | |
346 | source_read_size=strategies.integers(1, 16384), |
|
412 | original=strategies.sampled_from(random_input_data()), | |
347 | read_size=strategies.integers(1, zstd.COMPRESSION_RECOMMENDED_OUTPUT_SIZE)) |
|
413 | level=strategies.integers(min_value=1, max_value=5), | |
348 | def test_stream_source_readinto1(self, original, level, source_read_size, |
|
414 | source_read_size=strategies.integers(1, 16384), | |
349 | read_size): |
|
415 | read_size=strategies.integers(1, zstd.COMPRESSION_RECOMMENDED_OUTPUT_SIZE), | |
|
416 | ) | |||
|
417 | def test_stream_source_readinto1( | |||
|
418 | self, original, level, source_read_size, read_size | |||
|
419 | ): | |||
350 | if read_size == 0: |
|
420 | if read_size == 0: | |
351 | read_size = -1 |
|
421 | read_size = -1 | |
352 |
|
422 | |||
@@ -354,8 +424,9 b' class TestCompressor_stream_reader_fuzzi' | |||||
354 | ref_frame = refctx.compress(original) |
|
424 | ref_frame = refctx.compress(original) | |
355 |
|
425 | |||
356 | cctx = zstd.ZstdCompressor(level=level) |
|
426 | cctx = zstd.ZstdCompressor(level=level) | |
357 |
with cctx.stream_reader( |
|
427 | with cctx.stream_reader( | |
358 | read_size=source_read_size) as reader: |
|
428 | io.BytesIO(original), size=len(original), read_size=source_read_size | |
|
429 | ) as reader: | |||
359 | chunks = [] |
|
430 | chunks = [] | |
360 | while True: |
|
431 | while True: | |
361 | b = bytearray(read_size) |
|
432 | b = bytearray(read_size) | |
@@ -366,16 +437,20 b' class TestCompressor_stream_reader_fuzzi' | |||||
366 |
|
437 | |||
367 | chunks.append(bytes(b[0:count])) |
|
438 | chunks.append(bytes(b[0:count])) | |
368 |
|
439 | |||
369 |
self.assertEqual(b |
|
440 | self.assertEqual(b"".join(chunks), ref_frame) | |
370 |
|
441 | |||
371 | @hypothesis.settings( |
|
442 | @hypothesis.settings( | |
372 |
suppress_health_check=[hypothesis.HealthCheck.large_base_example] |
|
443 | suppress_health_check=[hypothesis.HealthCheck.large_base_example] | |
373 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
444 | ) | |
374 | level=strategies.integers(min_value=1, max_value=5), |
|
445 | @hypothesis.given( | |
375 | source_read_size=strategies.integers(1, 16384), |
|
446 | original=strategies.sampled_from(random_input_data()), | |
376 | read_size=strategies.integers(1, zstd.COMPRESSION_RECOMMENDED_OUTPUT_SIZE)) |
|
447 | level=strategies.integers(min_value=1, max_value=5), | |
377 | def test_buffer_source_readinto1(self, original, level, source_read_size, |
|
448 | source_read_size=strategies.integers(1, 16384), | |
378 | read_size): |
|
449 | read_size=strategies.integers(1, zstd.COMPRESSION_RECOMMENDED_OUTPUT_SIZE), | |
|
450 | ) | |||
|
451 | def test_buffer_source_readinto1( | |||
|
452 | self, original, level, source_read_size, read_size | |||
|
453 | ): | |||
379 | if read_size == 0: |
|
454 | if read_size == 0: | |
380 | read_size = -1 |
|
455 | read_size = -1 | |
381 |
|
456 | |||
@@ -383,8 +458,9 b' class TestCompressor_stream_reader_fuzzi' | |||||
383 | ref_frame = refctx.compress(original) |
|
458 | ref_frame = refctx.compress(original) | |
384 |
|
459 | |||
385 | cctx = zstd.ZstdCompressor(level=level) |
|
460 | cctx = zstd.ZstdCompressor(level=level) | |
386 |
with cctx.stream_reader( |
|
461 | with cctx.stream_reader( | |
387 | read_size=source_read_size) as reader: |
|
462 | original, size=len(original), read_size=source_read_size | |
|
463 | ) as reader: | |||
388 | chunks = [] |
|
464 | chunks = [] | |
389 | while True: |
|
465 | while True: | |
390 | b = bytearray(read_size) |
|
466 | b = bytearray(read_size) | |
@@ -395,22 +471,30 b' class TestCompressor_stream_reader_fuzzi' | |||||
395 |
|
471 | |||
396 | chunks.append(bytes(b[0:count])) |
|
472 | chunks.append(bytes(b[0:count])) | |
397 |
|
473 | |||
398 |
self.assertEqual(b |
|
474 | self.assertEqual(b"".join(chunks), ref_frame) | |
399 |
|
475 | |||
400 | @hypothesis.settings( |
|
476 | @hypothesis.settings( | |
401 | suppress_health_check=[hypothesis.HealthCheck.large_base_example]) |
|
477 | suppress_health_check=[ | |
402 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
478 | hypothesis.HealthCheck.large_base_example, | |
403 | level=strategies.integers(min_value=1, max_value=5), |
|
479 | hypothesis.HealthCheck.too_slow, | |
404 | source_read_size=strategies.integers(1, 16384), |
|
480 | ] | |
405 | read_sizes=strategies.data()) |
|
481 | ) | |
406 | def test_stream_source_readinto1_variance(self, original, level, source_read_size, |
|
482 | @hypothesis.given( | |
407 | read_sizes): |
|
483 | original=strategies.sampled_from(random_input_data()), | |
|
484 | level=strategies.integers(min_value=1, max_value=5), | |||
|
485 | source_read_size=strategies.integers(1, 16384), | |||
|
486 | read_sizes=strategies.data(), | |||
|
487 | ) | |||
|
488 | def test_stream_source_readinto1_variance( | |||
|
489 | self, original, level, source_read_size, read_sizes | |||
|
490 | ): | |||
408 | refctx = zstd.ZstdCompressor(level=level) |
|
491 | refctx = zstd.ZstdCompressor(level=level) | |
409 | ref_frame = refctx.compress(original) |
|
492 | ref_frame = refctx.compress(original) | |
410 |
|
493 | |||
411 | cctx = zstd.ZstdCompressor(level=level) |
|
494 | cctx = zstd.ZstdCompressor(level=level) | |
412 |
with cctx.stream_reader( |
|
495 | with cctx.stream_reader( | |
413 | read_size=source_read_size) as reader: |
|
496 | io.BytesIO(original), size=len(original), read_size=source_read_size | |
|
497 | ) as reader: | |||
414 | chunks = [] |
|
498 | chunks = [] | |
415 | while True: |
|
499 | while True: | |
416 | read_size = read_sizes.draw(strategies.integers(1, 16384)) |
|
500 | read_size = read_sizes.draw(strategies.integers(1, 16384)) | |
@@ -422,23 +506,31 b' class TestCompressor_stream_reader_fuzzi' | |||||
422 |
|
506 | |||
423 | chunks.append(bytes(b[0:count])) |
|
507 | chunks.append(bytes(b[0:count])) | |
424 |
|
508 | |||
425 |
self.assertEqual(b |
|
509 | self.assertEqual(b"".join(chunks), ref_frame) | |
426 |
|
510 | |||
427 | @hypothesis.settings( |
|
511 | @hypothesis.settings( | |
428 | suppress_health_check=[hypothesis.HealthCheck.large_base_example]) |
|
512 | suppress_health_check=[ | |
429 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
513 | hypothesis.HealthCheck.large_base_example, | |
430 | level=strategies.integers(min_value=1, max_value=5), |
|
514 | hypothesis.HealthCheck.too_slow, | |
431 | source_read_size=strategies.integers(1, 16384), |
|
515 | ] | |
432 | read_sizes=strategies.data()) |
|
516 | ) | |
433 | def test_buffer_source_readinto1_variance(self, original, level, source_read_size, |
|
517 | @hypothesis.given( | |
434 | read_sizes): |
|
518 | original=strategies.sampled_from(random_input_data()), | |
|
519 | level=strategies.integers(min_value=1, max_value=5), | |||
|
520 | source_read_size=strategies.integers(1, 16384), | |||
|
521 | read_sizes=strategies.data(), | |||
|
522 | ) | |||
|
523 | def test_buffer_source_readinto1_variance( | |||
|
524 | self, original, level, source_read_size, read_sizes | |||
|
525 | ): | |||
435 |
|
526 | |||
436 | refctx = zstd.ZstdCompressor(level=level) |
|
527 | refctx = zstd.ZstdCompressor(level=level) | |
437 | ref_frame = refctx.compress(original) |
|
528 | ref_frame = refctx.compress(original) | |
438 |
|
529 | |||
439 | cctx = zstd.ZstdCompressor(level=level) |
|
530 | cctx = zstd.ZstdCompressor(level=level) | |
440 |
with cctx.stream_reader( |
|
531 | with cctx.stream_reader( | |
441 | read_size=source_read_size) as reader: |
|
532 | original, size=len(original), read_size=source_read_size | |
|
533 | ) as reader: | |||
442 | chunks = [] |
|
534 | chunks = [] | |
443 | while True: |
|
535 | while True: | |
444 | read_size = read_sizes.draw(strategies.integers(1, 16384)) |
|
536 | read_size = read_sizes.draw(strategies.integers(1, 16384)) | |
@@ -450,35 +542,40 b' class TestCompressor_stream_reader_fuzzi' | |||||
450 |
|
542 | |||
451 | chunks.append(bytes(b[0:count])) |
|
543 | chunks.append(bytes(b[0:count])) | |
452 |
|
544 | |||
453 |
self.assertEqual(b |
|
545 | self.assertEqual(b"".join(chunks), ref_frame) | |
454 |
|
||||
455 |
|
546 | |||
456 |
|
547 | |||
457 |
@unittest.skipUnless( |
|
548 | @unittest.skipUnless("ZSTD_SLOW_TESTS" in os.environ, "ZSTD_SLOW_TESTS not set") | |
458 | @make_cffi |
|
549 | @make_cffi | |
459 |
class TestCompressor_stream_writer_fuzzing( |
|
550 | class TestCompressor_stream_writer_fuzzing(TestCase): | |
460 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
551 | @hypothesis.given( | |
461 | level=strategies.integers(min_value=1, max_value=5), |
|
552 | original=strategies.sampled_from(random_input_data()), | |
462 |
|
|
553 | level=strategies.integers(min_value=1, max_value=5), | |
|
554 | write_size=strategies.integers(min_value=1, max_value=1048576), | |||
|
555 | ) | |||
463 | def test_write_size_variance(self, original, level, write_size): |
|
556 | def test_write_size_variance(self, original, level, write_size): | |
464 | refctx = zstd.ZstdCompressor(level=level) |
|
557 | refctx = zstd.ZstdCompressor(level=level) | |
465 | ref_frame = refctx.compress(original) |
|
558 | ref_frame = refctx.compress(original) | |
466 |
|
559 | |||
467 | cctx = zstd.ZstdCompressor(level=level) |
|
560 | cctx = zstd.ZstdCompressor(level=level) | |
468 | b = NonClosingBytesIO() |
|
561 | b = NonClosingBytesIO() | |
469 | with cctx.stream_writer(b, size=len(original), write_size=write_size) as compressor: |
|
562 | with cctx.stream_writer( | |
|
563 | b, size=len(original), write_size=write_size | |||
|
564 | ) as compressor: | |||
470 | compressor.write(original) |
|
565 | compressor.write(original) | |
471 |
|
566 | |||
472 | self.assertEqual(b.getvalue(), ref_frame) |
|
567 | self.assertEqual(b.getvalue(), ref_frame) | |
473 |
|
568 | |||
474 |
|
569 | |||
475 |
@unittest.skipUnless( |
|
570 | @unittest.skipUnless("ZSTD_SLOW_TESTS" in os.environ, "ZSTD_SLOW_TESTS not set") | |
476 | @make_cffi |
|
571 | @make_cffi | |
477 |
class TestCompressor_copy_stream_fuzzing( |
|
572 | class TestCompressor_copy_stream_fuzzing(TestCase): | |
478 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
573 | @hypothesis.given( | |
479 | level=strategies.integers(min_value=1, max_value=5), |
|
574 | original=strategies.sampled_from(random_input_data()), | |
480 |
|
|
575 | level=strategies.integers(min_value=1, max_value=5), | |
481 |
|
|
576 | read_size=strategies.integers(min_value=1, max_value=1048576), | |
|
577 | write_size=strategies.integers(min_value=1, max_value=1048576), | |||
|
578 | ) | |||
482 | def test_read_write_size_variance(self, original, level, read_size, write_size): |
|
579 | def test_read_write_size_variance(self, original, level, read_size, write_size): | |
483 | refctx = zstd.ZstdCompressor(level=level) |
|
580 | refctx = zstd.ZstdCompressor(level=level) | |
484 | ref_frame = refctx.compress(original) |
|
581 | ref_frame = refctx.compress(original) | |
@@ -487,20 +584,27 b' class TestCompressor_copy_stream_fuzzing' | |||||
487 | source = io.BytesIO(original) |
|
584 | source = io.BytesIO(original) | |
488 | dest = io.BytesIO() |
|
585 | dest = io.BytesIO() | |
489 |
|
586 | |||
490 | cctx.copy_stream(source, dest, size=len(original), read_size=read_size, |
|
587 | cctx.copy_stream( | |
491 | write_size=write_size) |
|
588 | source, dest, size=len(original), read_size=read_size, write_size=write_size | |
|
589 | ) | |||
492 |
|
590 | |||
493 | self.assertEqual(dest.getvalue(), ref_frame) |
|
591 | self.assertEqual(dest.getvalue(), ref_frame) | |
494 |
|
592 | |||
495 |
|
593 | |||
496 |
@unittest.skipUnless( |
|
594 | @unittest.skipUnless("ZSTD_SLOW_TESTS" in os.environ, "ZSTD_SLOW_TESTS not set") | |
497 | @make_cffi |
|
595 | @make_cffi | |
498 |
class TestCompressor_compressobj_fuzzing( |
|
596 | class TestCompressor_compressobj_fuzzing(TestCase): | |
499 | @hypothesis.settings( |
|
597 | @hypothesis.settings( | |
500 | suppress_health_check=[hypothesis.HealthCheck.large_base_example]) |
|
598 | suppress_health_check=[ | |
501 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
599 | hypothesis.HealthCheck.large_base_example, | |
502 | level=strategies.integers(min_value=1, max_value=5), |
|
600 | hypothesis.HealthCheck.too_slow, | |
503 | chunk_sizes=strategies.data()) |
|
601 | ] | |
|
602 | ) | |||
|
603 | @hypothesis.given( | |||
|
604 | original=strategies.sampled_from(random_input_data()), | |||
|
605 | level=strategies.integers(min_value=1, max_value=5), | |||
|
606 | chunk_sizes=strategies.data(), | |||
|
607 | ) | |||
504 | def test_random_input_sizes(self, original, level, chunk_sizes): |
|
608 | def test_random_input_sizes(self, original, level, chunk_sizes): | |
505 | refctx = zstd.ZstdCompressor(level=level) |
|
609 | refctx = zstd.ZstdCompressor(level=level) | |
506 | ref_frame = refctx.compress(original) |
|
610 | ref_frame = refctx.compress(original) | |
@@ -512,7 +616,7 b' class TestCompressor_compressobj_fuzzing' | |||||
512 | i = 0 |
|
616 | i = 0 | |
513 | while True: |
|
617 | while True: | |
514 | chunk_size = chunk_sizes.draw(strategies.integers(1, 4096)) |
|
618 | chunk_size = chunk_sizes.draw(strategies.integers(1, 4096)) | |
515 | source = original[i:i + chunk_size] |
|
619 | source = original[i : i + chunk_size] | |
516 | if not source: |
|
620 | if not source: | |
517 | break |
|
621 | break | |
518 |
|
622 | |||
@@ -521,14 +625,20 b' class TestCompressor_compressobj_fuzzing' | |||||
521 |
|
625 | |||
522 | chunks.append(cobj.flush()) |
|
626 | chunks.append(cobj.flush()) | |
523 |
|
627 | |||
524 |
self.assertEqual(b |
|
628 | self.assertEqual(b"".join(chunks), ref_frame) | |
525 |
|
629 | |||
526 | @hypothesis.settings( |
|
630 | @hypothesis.settings( | |
527 | suppress_health_check=[hypothesis.HealthCheck.large_base_example]) |
|
631 | suppress_health_check=[ | |
528 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
632 | hypothesis.HealthCheck.large_base_example, | |
529 | level=strategies.integers(min_value=1, max_value=5), |
|
633 | hypothesis.HealthCheck.too_slow, | |
530 | chunk_sizes=strategies.data(), |
|
634 | ] | |
531 | flushes=strategies.data()) |
|
635 | ) | |
|
636 | @hypothesis.given( | |||
|
637 | original=strategies.sampled_from(random_input_data()), | |||
|
638 | level=strategies.integers(min_value=1, max_value=5), | |||
|
639 | chunk_sizes=strategies.data(), | |||
|
640 | flushes=strategies.data(), | |||
|
641 | ) | |||
532 | def test_flush_block(self, original, level, chunk_sizes, flushes): |
|
642 | def test_flush_block(self, original, level, chunk_sizes, flushes): | |
533 | cctx = zstd.ZstdCompressor(level=level) |
|
643 | cctx = zstd.ZstdCompressor(level=level) | |
534 | cobj = cctx.compressobj() |
|
644 | cobj = cctx.compressobj() | |
@@ -541,7 +651,7 b' class TestCompressor_compressobj_fuzzing' | |||||
541 | i = 0 |
|
651 | i = 0 | |
542 | while True: |
|
652 | while True: | |
543 | input_size = chunk_sizes.draw(strategies.integers(1, 4096)) |
|
653 | input_size = chunk_sizes.draw(strategies.integers(1, 4096)) | |
544 | source = original[i:i + input_size] |
|
654 | source = original[i : i + input_size] | |
545 | if not source: |
|
655 | if not source: | |
546 | break |
|
656 | break | |
547 |
|
657 | |||
@@ -558,24 +668,28 b' class TestCompressor_compressobj_fuzzing' | |||||
558 | compressed_chunks.append(chunk) |
|
668 | compressed_chunks.append(chunk) | |
559 | decompressed_chunks.append(dobj.decompress(chunk)) |
|
669 | decompressed_chunks.append(dobj.decompress(chunk)) | |
560 |
|
670 | |||
561 |
self.assertEqual(b |
|
671 | self.assertEqual(b"".join(decompressed_chunks), original[0:i]) | |
562 |
|
672 | |||
563 | chunk = cobj.flush(zstd.COMPRESSOBJ_FLUSH_FINISH) |
|
673 | chunk = cobj.flush(zstd.COMPRESSOBJ_FLUSH_FINISH) | |
564 | compressed_chunks.append(chunk) |
|
674 | compressed_chunks.append(chunk) | |
565 | decompressed_chunks.append(dobj.decompress(chunk)) |
|
675 | decompressed_chunks.append(dobj.decompress(chunk)) | |
566 |
|
676 | |||
567 | self.assertEqual(dctx.decompress(b''.join(compressed_chunks), |
|
677 | self.assertEqual( | |
568 | max_output_size=len(original)), |
|
678 | dctx.decompress(b"".join(compressed_chunks), max_output_size=len(original)), | |
569 |
|
|
679 | original, | |
570 | self.assertEqual(b''.join(decompressed_chunks), original) |
|
680 | ) | |
|
681 | self.assertEqual(b"".join(decompressed_chunks), original) | |||
|
682 | ||||
571 |
|
683 | |||
572 |
@unittest.skipUnless( |
|
684 | @unittest.skipUnless("ZSTD_SLOW_TESTS" in os.environ, "ZSTD_SLOW_TESTS not set") | |
573 | @make_cffi |
|
685 | @make_cffi | |
574 |
class TestCompressor_read_to_iter_fuzzing( |
|
686 | class TestCompressor_read_to_iter_fuzzing(TestCase): | |
575 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
687 | @hypothesis.given( | |
576 | level=strategies.integers(min_value=1, max_value=5), |
|
688 | original=strategies.sampled_from(random_input_data()), | |
577 |
|
|
689 | level=strategies.integers(min_value=1, max_value=5), | |
578 |
|
|
690 | read_size=strategies.integers(min_value=1, max_value=4096), | |
|
691 | write_size=strategies.integers(min_value=1, max_value=4096), | |||
|
692 | ) | |||
579 | def test_read_write_size_variance(self, original, level, read_size, write_size): |
|
693 | def test_read_write_size_variance(self, original, level, read_size, write_size): | |
580 | refcctx = zstd.ZstdCompressor(level=level) |
|
694 | refcctx = zstd.ZstdCompressor(level=level) | |
581 | ref_frame = refcctx.compress(original) |
|
695 | ref_frame = refcctx.compress(original) | |
@@ -583,32 +697,35 b' class TestCompressor_read_to_iter_fuzzin' | |||||
583 | source = io.BytesIO(original) |
|
697 | source = io.BytesIO(original) | |
584 |
|
698 | |||
585 | cctx = zstd.ZstdCompressor(level=level) |
|
699 | cctx = zstd.ZstdCompressor(level=level) | |
586 | chunks = list(cctx.read_to_iter(source, size=len(original), |
|
700 | chunks = list( | |
587 | read_size=read_size, |
|
701 | cctx.read_to_iter( | |
588 | write_size=write_size)) |
|
702 | source, size=len(original), read_size=read_size, write_size=write_size | |
|
703 | ) | |||
|
704 | ) | |||
589 |
|
705 | |||
590 |
self.assertEqual(b |
|
706 | self.assertEqual(b"".join(chunks), ref_frame) | |
591 |
|
707 | |||
592 |
|
708 | |||
593 |
@unittest.skipUnless( |
|
709 | @unittest.skipUnless("ZSTD_SLOW_TESTS" in os.environ, "ZSTD_SLOW_TESTS not set") | |
594 |
class TestCompressor_multi_compress_to_buffer_fuzzing( |
|
710 | class TestCompressor_multi_compress_to_buffer_fuzzing(TestCase): | |
595 | @hypothesis.given(original=strategies.lists(strategies.sampled_from(random_input_data()), |
|
711 | @hypothesis.given( | |
596 | min_size=1, max_size=1024), |
|
712 | original=strategies.lists( | |
597 | threads=strategies.integers(min_value=1, max_value=8), |
|
713 | strategies.sampled_from(random_input_data()), min_size=1, max_size=1024 | |
598 | use_dict=strategies.booleans()) |
|
714 | ), | |
|
715 | threads=strategies.integers(min_value=1, max_value=8), | |||
|
716 | use_dict=strategies.booleans(), | |||
|
717 | ) | |||
599 | def test_data_equivalence(self, original, threads, use_dict): |
|
718 | def test_data_equivalence(self, original, threads, use_dict): | |
600 | kwargs = {} |
|
719 | kwargs = {} | |
601 |
|
720 | |||
602 | # Use a content dictionary because it is cheap to create. |
|
721 | # Use a content dictionary because it is cheap to create. | |
603 | if use_dict: |
|
722 | if use_dict: | |
604 |
kwargs[ |
|
723 | kwargs["dict_data"] = zstd.ZstdCompressionDict(original[0]) | |
605 |
|
724 | |||
606 | cctx = zstd.ZstdCompressor(level=1, |
|
725 | cctx = zstd.ZstdCompressor(level=1, write_checksum=True, **kwargs) | |
607 | write_checksum=True, |
|
|||
608 | **kwargs) |
|
|||
609 |
|
726 | |||
610 |
if not hasattr(cctx, |
|
727 | if not hasattr(cctx, "multi_compress_to_buffer"): | |
611 |
self.skipTest( |
|
728 | self.skipTest("multi_compress_to_buffer not available") | |
612 |
|
729 | |||
613 | result = cctx.multi_compress_to_buffer(original, threads=-1) |
|
730 | result = cctx.multi_compress_to_buffer(original, threads=-1) | |
614 |
|
731 | |||
@@ -624,17 +741,21 b' class TestCompressor_multi_compress_to_b' | |||||
624 | self.assertEqual(dctx.decompress(frame), original[i]) |
|
741 | self.assertEqual(dctx.decompress(frame), original[i]) | |
625 |
|
742 | |||
626 |
|
743 | |||
627 |
@unittest.skipUnless( |
|
744 | @unittest.skipUnless("ZSTD_SLOW_TESTS" in os.environ, "ZSTD_SLOW_TESTS not set") | |
628 | @make_cffi |
|
745 | @make_cffi | |
629 |
class TestCompressor_chunker_fuzzing( |
|
746 | class TestCompressor_chunker_fuzzing(TestCase): | |
630 | @hypothesis.settings( |
|
747 | @hypothesis.settings( | |
631 | suppress_health_check=[hypothesis.HealthCheck.large_base_example]) |
|
748 | suppress_health_check=[ | |
632 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
749 | hypothesis.HealthCheck.large_base_example, | |
633 | level=strategies.integers(min_value=1, max_value=5), |
|
750 | hypothesis.HealthCheck.too_slow, | |
634 | chunk_size=strategies.integers( |
|
751 | ] | |
635 | min_value=1, |
|
752 | ) | |
636 | max_value=32 * 1048576), |
|
753 | @hypothesis.given( | |
637 | input_sizes=strategies.data()) |
|
754 | original=strategies.sampled_from(random_input_data()), | |
|
755 | level=strategies.integers(min_value=1, max_value=5), | |||
|
756 | chunk_size=strategies.integers(min_value=1, max_value=32 * 1048576), | |||
|
757 | input_sizes=strategies.data(), | |||
|
758 | ) | |||
638 | def test_random_input_sizes(self, original, level, chunk_size, input_sizes): |
|
759 | def test_random_input_sizes(self, original, level, chunk_size, input_sizes): | |
639 | cctx = zstd.ZstdCompressor(level=level) |
|
760 | cctx = zstd.ZstdCompressor(level=level) | |
640 | chunker = cctx.chunker(chunk_size=chunk_size) |
|
761 | chunker = cctx.chunker(chunk_size=chunk_size) | |
@@ -643,7 +764,7 b' class TestCompressor_chunker_fuzzing(uni' | |||||
643 | i = 0 |
|
764 | i = 0 | |
644 | while True: |
|
765 | while True: | |
645 | input_size = input_sizes.draw(strategies.integers(1, 4096)) |
|
766 | input_size = input_sizes.draw(strategies.integers(1, 4096)) | |
646 | source = original[i:i + input_size] |
|
767 | source = original[i : i + input_size] | |
647 | if not source: |
|
768 | if not source: | |
648 | break |
|
769 | break | |
649 |
|
770 | |||
@@ -654,23 +775,26 b' class TestCompressor_chunker_fuzzing(uni' | |||||
654 |
|
775 | |||
655 | dctx = zstd.ZstdDecompressor() |
|
776 | dctx = zstd.ZstdDecompressor() | |
656 |
|
777 | |||
657 |
self.assertEqual( |
|
778 | self.assertEqual( | |
658 | max_output_size=len(original)), |
|
779 | dctx.decompress(b"".join(chunks), max_output_size=len(original)), original | |
659 | original) |
|
780 | ) | |
660 |
|
781 | |||
661 | self.assertTrue(all(len(chunk) == chunk_size for chunk in chunks[:-1])) |
|
782 | self.assertTrue(all(len(chunk) == chunk_size for chunk in chunks[:-1])) | |
662 |
|
783 | |||
663 | @hypothesis.settings( |
|
784 | @hypothesis.settings( | |
664 | suppress_health_check=[hypothesis.HealthCheck.large_base_example]) |
|
785 | suppress_health_check=[ | |
665 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
786 | hypothesis.HealthCheck.large_base_example, | |
666 | level=strategies.integers(min_value=1, max_value=5), |
|
787 | hypothesis.HealthCheck.too_slow, | |
667 | chunk_size=strategies.integers( |
|
788 | ] | |
668 | min_value=1, |
|
789 | ) | |
669 | max_value=32 * 1048576), |
|
790 | @hypothesis.given( | |
670 | input_sizes=strategies.data(), |
|
791 | original=strategies.sampled_from(random_input_data()), | |
671 | flushes=strategies.data()) |
|
792 | level=strategies.integers(min_value=1, max_value=5), | |
672 | def test_flush_block(self, original, level, chunk_size, input_sizes, |
|
793 | chunk_size=strategies.integers(min_value=1, max_value=32 * 1048576), | |
673 | flushes): |
|
794 | input_sizes=strategies.data(), | |
|
795 | flushes=strategies.data(), | |||
|
796 | ) | |||
|
797 | def test_flush_block(self, original, level, chunk_size, input_sizes, flushes): | |||
674 | cctx = zstd.ZstdCompressor(level=level) |
|
798 | cctx = zstd.ZstdCompressor(level=level) | |
675 | chunker = cctx.chunker(chunk_size=chunk_size) |
|
799 | chunker = cctx.chunker(chunk_size=chunk_size) | |
676 |
|
800 | |||
@@ -682,7 +806,7 b' class TestCompressor_chunker_fuzzing(uni' | |||||
682 | i = 0 |
|
806 | i = 0 | |
683 | while True: |
|
807 | while True: | |
684 | input_size = input_sizes.draw(strategies.integers(1, 4096)) |
|
808 | input_size = input_sizes.draw(strategies.integers(1, 4096)) | |
685 | source = original[i:i + input_size] |
|
809 | source = original[i : i + input_size] | |
686 | if not source: |
|
810 | if not source: | |
687 | break |
|
811 | break | |
688 |
|
812 | |||
@@ -690,22 +814,23 b' class TestCompressor_chunker_fuzzing(uni' | |||||
690 |
|
814 | |||
691 | chunks = list(chunker.compress(source)) |
|
815 | chunks = list(chunker.compress(source)) | |
692 | compressed_chunks.extend(chunks) |
|
816 | compressed_chunks.extend(chunks) | |
693 |
decompressed_chunks.append(dobj.decompress(b |
|
817 | decompressed_chunks.append(dobj.decompress(b"".join(chunks))) | |
694 |
|
818 | |||
695 | if not flushes.draw(strategies.booleans()): |
|
819 | if not flushes.draw(strategies.booleans()): | |
696 | continue |
|
820 | continue | |
697 |
|
821 | |||
698 | chunks = list(chunker.flush()) |
|
822 | chunks = list(chunker.flush()) | |
699 | compressed_chunks.extend(chunks) |
|
823 | compressed_chunks.extend(chunks) | |
700 |
decompressed_chunks.append(dobj.decompress(b |
|
824 | decompressed_chunks.append(dobj.decompress(b"".join(chunks))) | |
701 |
|
825 | |||
702 |
self.assertEqual(b |
|
826 | self.assertEqual(b"".join(decompressed_chunks), original[0:i]) | |
703 |
|
827 | |||
704 | chunks = list(chunker.finish()) |
|
828 | chunks = list(chunker.finish()) | |
705 | compressed_chunks.extend(chunks) |
|
829 | compressed_chunks.extend(chunks) | |
706 |
decompressed_chunks.append(dobj.decompress(b |
|
830 | decompressed_chunks.append(dobj.decompress(b"".join(chunks))) | |
707 |
|
831 | |||
708 | self.assertEqual(dctx.decompress(b''.join(compressed_chunks), |
|
832 | self.assertEqual( | |
709 | max_output_size=len(original)), |
|
833 | dctx.decompress(b"".join(compressed_chunks), max_output_size=len(original)), | |
710 |
|
|
834 | original, | |
711 | self.assertEqual(b''.join(decompressed_chunks), original) No newline at end of file |
|
835 | ) | |
|
836 | self.assertEqual(b"".join(decompressed_chunks), original) |
@@ -3,29 +3,34 b' import unittest' | |||||
3 |
|
3 | |||
4 | import zstandard as zstd |
|
4 | import zstandard as zstd | |
5 |
|
5 | |||
6 |
from . |
|
6 | from .common import ( | |
7 | make_cffi, |
|
7 | make_cffi, | |
|
8 | TestCase, | |||
8 | ) |
|
9 | ) | |
9 |
|
10 | |||
10 |
|
11 | |||
11 | @make_cffi |
|
12 | @make_cffi | |
12 |
class TestCompressionParameters( |
|
13 | class TestCompressionParameters(TestCase): | |
13 | def test_bounds(self): |
|
14 | def test_bounds(self): | |
14 |
zstd.ZstdCompressionParameters( |
|
15 | zstd.ZstdCompressionParameters( | |
15 |
|
|
16 | window_log=zstd.WINDOWLOG_MIN, | |
16 |
|
|
17 | chain_log=zstd.CHAINLOG_MIN, | |
17 |
|
|
18 | hash_log=zstd.HASHLOG_MIN, | |
18 | min_match=zstd.MINMATCH_MIN + 1, |
|
19 | search_log=zstd.SEARCHLOG_MIN, | |
19 | target_length=zstd.TARGETLENGTH_MIN, |
|
20 | min_match=zstd.MINMATCH_MIN + 1, | |
20 | strategy=zstd.STRATEGY_FAST) |
|
21 | target_length=zstd.TARGETLENGTH_MIN, | |
|
22 | strategy=zstd.STRATEGY_FAST, | |||
|
23 | ) | |||
21 |
|
24 | |||
22 |
zstd.ZstdCompressionParameters( |
|
25 | zstd.ZstdCompressionParameters( | |
23 |
|
|
26 | window_log=zstd.WINDOWLOG_MAX, | |
24 |
|
|
27 | chain_log=zstd.CHAINLOG_MAX, | |
25 |
|
|
28 | hash_log=zstd.HASHLOG_MAX, | |
26 | min_match=zstd.MINMATCH_MAX - 1, |
|
29 | search_log=zstd.SEARCHLOG_MAX, | |
27 | target_length=zstd.TARGETLENGTH_MAX, |
|
30 | min_match=zstd.MINMATCH_MAX - 1, | |
28 | strategy=zstd.STRATEGY_BTULTRA2) |
|
31 | target_length=zstd.TARGETLENGTH_MAX, | |
|
32 | strategy=zstd.STRATEGY_BTULTRA2, | |||
|
33 | ) | |||
29 |
|
34 | |||
30 | def test_from_level(self): |
|
35 | def test_from_level(self): | |
31 | p = zstd.ZstdCompressionParameters.from_level(1) |
|
36 | p = zstd.ZstdCompressionParameters.from_level(1) | |
@@ -37,13 +42,15 b' class TestCompressionParameters(unittest' | |||||
37 | self.assertEqual(p.window_log, 19) |
|
42 | self.assertEqual(p.window_log, 19) | |
38 |
|
43 | |||
39 | def test_members(self): |
|
44 | def test_members(self): | |
40 |
p = zstd.ZstdCompressionParameters( |
|
45 | p = zstd.ZstdCompressionParameters( | |
41 | chain_log=6, |
|
46 | window_log=10, | |
42 | hash_log=7, |
|
47 | chain_log=6, | |
43 | search_log=4, |
|
48 | hash_log=7, | |
44 | min_match=5, |
|
49 | search_log=4, | |
45 | target_length=8, |
|
50 | min_match=5, | |
46 | strategy=1) |
|
51 | target_length=8, | |
|
52 | strategy=1, | |||
|
53 | ) | |||
47 | self.assertEqual(p.window_log, 10) |
|
54 | self.assertEqual(p.window_log, 10) | |
48 | self.assertEqual(p.chain_log, 6) |
|
55 | self.assertEqual(p.chain_log, 6) | |
49 | self.assertEqual(p.hash_log, 7) |
|
56 | self.assertEqual(p.hash_log, 7) | |
@@ -58,8 +65,7 b' class TestCompressionParameters(unittest' | |||||
58 | p = zstd.ZstdCompressionParameters(threads=4) |
|
65 | p = zstd.ZstdCompressionParameters(threads=4) | |
59 | self.assertEqual(p.threads, 4) |
|
66 | self.assertEqual(p.threads, 4) | |
60 |
|
67 | |||
61 | p = zstd.ZstdCompressionParameters(threads=2, job_size=1048576, |
|
68 | p = zstd.ZstdCompressionParameters(threads=2, job_size=1048576, overlap_log=6) | |
62 | overlap_log=6) |
|
|||
63 | self.assertEqual(p.threads, 2) |
|
69 | self.assertEqual(p.threads, 2) | |
64 | self.assertEqual(p.job_size, 1048576) |
|
70 | self.assertEqual(p.job_size, 1048576) | |
65 | self.assertEqual(p.overlap_log, 6) |
|
71 | self.assertEqual(p.overlap_log, 6) | |
@@ -91,20 +97,25 b' class TestCompressionParameters(unittest' | |||||
91 | self.assertEqual(p.ldm_hash_rate_log, 8) |
|
97 | self.assertEqual(p.ldm_hash_rate_log, 8) | |
92 |
|
98 | |||
93 | def test_estimated_compression_context_size(self): |
|
99 | def test_estimated_compression_context_size(self): | |
94 |
p = zstd.ZstdCompressionParameters( |
|
100 | p = zstd.ZstdCompressionParameters( | |
95 | chain_log=16, |
|
101 | window_log=20, | |
96 | hash_log=17, |
|
102 | chain_log=16, | |
97 | search_log=1, |
|
103 | hash_log=17, | |
98 | min_match=5, |
|
104 | search_log=1, | |
99 | target_length=16, |
|
105 | min_match=5, | |
100 | strategy=zstd.STRATEGY_DFAST) |
|
106 | target_length=16, | |
|
107 | strategy=zstd.STRATEGY_DFAST, | |||
|
108 | ) | |||
101 |
|
109 | |||
102 | # 32-bit has slightly different values from 64-bit. |
|
110 | # 32-bit has slightly different values from 64-bit. | |
103 | self.assertAlmostEqual(p.estimated_compression_context_size(), 1294144, |
|
111 | self.assertAlmostEqual( | |
104 | delta=250) |
|
112 | p.estimated_compression_context_size(), 1294464, delta=400 | |
|
113 | ) | |||
105 |
|
114 | |||
106 | def test_strategy(self): |
|
115 | def test_strategy(self): | |
107 | with self.assertRaisesRegexp(ValueError, 'cannot specify both compression_strategy'): |
|
116 | with self.assertRaisesRegex( | |
|
117 | ValueError, "cannot specify both compression_strategy" | |||
|
118 | ): | |||
108 | zstd.ZstdCompressionParameters(strategy=0, compression_strategy=0) |
|
119 | zstd.ZstdCompressionParameters(strategy=0, compression_strategy=0) | |
109 |
|
120 | |||
110 | p = zstd.ZstdCompressionParameters(strategy=2) |
|
121 | p = zstd.ZstdCompressionParameters(strategy=2) | |
@@ -114,7 +125,9 b' class TestCompressionParameters(unittest' | |||||
114 | self.assertEqual(p.compression_strategy, 3) |
|
125 | self.assertEqual(p.compression_strategy, 3) | |
115 |
|
126 | |||
116 | def test_ldm_hash_rate_log(self): |
|
127 | def test_ldm_hash_rate_log(self): | |
117 | with self.assertRaisesRegexp(ValueError, 'cannot specify both ldm_hash_rate_log'): |
|
128 | with self.assertRaisesRegex( | |
|
129 | ValueError, "cannot specify both ldm_hash_rate_log" | |||
|
130 | ): | |||
118 | zstd.ZstdCompressionParameters(ldm_hash_rate_log=8, ldm_hash_every_log=4) |
|
131 | zstd.ZstdCompressionParameters(ldm_hash_rate_log=8, ldm_hash_every_log=4) | |
119 |
|
132 | |||
120 | p = zstd.ZstdCompressionParameters(ldm_hash_rate_log=8) |
|
133 | p = zstd.ZstdCompressionParameters(ldm_hash_rate_log=8) | |
@@ -124,7 +137,7 b' class TestCompressionParameters(unittest' | |||||
124 | self.assertEqual(p.ldm_hash_every_log, 16) |
|
137 | self.assertEqual(p.ldm_hash_every_log, 16) | |
125 |
|
138 | |||
126 | def test_overlap_log(self): |
|
139 | def test_overlap_log(self): | |
127 |
with self.assertRaisesRegex |
|
140 | with self.assertRaisesRegex(ValueError, "cannot specify both overlap_log"): | |
128 | zstd.ZstdCompressionParameters(overlap_log=1, overlap_size_log=9) |
|
141 | zstd.ZstdCompressionParameters(overlap_log=1, overlap_size_log=9) | |
129 |
|
142 | |||
130 | p = zstd.ZstdCompressionParameters(overlap_log=2) |
|
143 | p = zstd.ZstdCompressionParameters(overlap_log=2) | |
@@ -137,7 +150,7 b' class TestCompressionParameters(unittest' | |||||
137 |
|
150 | |||
138 |
|
151 | |||
139 | @make_cffi |
|
152 | @make_cffi | |
140 |
class TestFrameParameters( |
|
153 | class TestFrameParameters(TestCase): | |
141 | def test_invalid_type(self): |
|
154 | def test_invalid_type(self): | |
142 | with self.assertRaises(TypeError): |
|
155 | with self.assertRaises(TypeError): | |
143 | zstd.get_frame_parameters(None) |
|
156 | zstd.get_frame_parameters(None) | |
@@ -145,71 +158,71 b' class TestFrameParameters(unittest.TestC' | |||||
145 | # Python 3 doesn't appear to convert unicode to Py_buffer. |
|
158 | # Python 3 doesn't appear to convert unicode to Py_buffer. | |
146 | if sys.version_info[0] >= 3: |
|
159 | if sys.version_info[0] >= 3: | |
147 | with self.assertRaises(TypeError): |
|
160 | with self.assertRaises(TypeError): | |
148 |
zstd.get_frame_parameters(u |
|
161 | zstd.get_frame_parameters(u"foobarbaz") | |
149 | else: |
|
162 | else: | |
150 | # CPython will convert unicode to Py_buffer. But CFFI won't. |
|
163 | # CPython will convert unicode to Py_buffer. But CFFI won't. | |
151 |
if zstd.backend == |
|
164 | if zstd.backend == "cffi": | |
152 | with self.assertRaises(TypeError): |
|
165 | with self.assertRaises(TypeError): | |
153 |
zstd.get_frame_parameters(u |
|
166 | zstd.get_frame_parameters(u"foobarbaz") | |
154 | else: |
|
167 | else: | |
155 | with self.assertRaises(zstd.ZstdError): |
|
168 | with self.assertRaises(zstd.ZstdError): | |
156 |
zstd.get_frame_parameters(u |
|
169 | zstd.get_frame_parameters(u"foobarbaz") | |
157 |
|
170 | |||
158 | def test_invalid_input_sizes(self): |
|
171 | def test_invalid_input_sizes(self): | |
159 |
with self.assertRaisesRegex |
|
172 | with self.assertRaisesRegex(zstd.ZstdError, "not enough data for frame"): | |
160 |
zstd.get_frame_parameters(b |
|
173 | zstd.get_frame_parameters(b"") | |
161 |
|
174 | |||
162 |
with self.assertRaisesRegex |
|
175 | with self.assertRaisesRegex(zstd.ZstdError, "not enough data for frame"): | |
163 | zstd.get_frame_parameters(zstd.FRAME_HEADER) |
|
176 | zstd.get_frame_parameters(zstd.FRAME_HEADER) | |
164 |
|
177 | |||
165 | def test_invalid_frame(self): |
|
178 | def test_invalid_frame(self): | |
166 |
with self.assertRaisesRegex |
|
179 | with self.assertRaisesRegex(zstd.ZstdError, "Unknown frame descriptor"): | |
167 |
zstd.get_frame_parameters(b |
|
180 | zstd.get_frame_parameters(b"foobarbaz") | |
168 |
|
181 | |||
169 | def test_attributes(self): |
|
182 | def test_attributes(self): | |
170 |
params = zstd.get_frame_parameters(zstd.FRAME_HEADER + b |
|
183 | params = zstd.get_frame_parameters(zstd.FRAME_HEADER + b"\x00\x00") | |
171 | self.assertEqual(params.content_size, zstd.CONTENTSIZE_UNKNOWN) |
|
184 | self.assertEqual(params.content_size, zstd.CONTENTSIZE_UNKNOWN) | |
172 | self.assertEqual(params.window_size, 1024) |
|
185 | self.assertEqual(params.window_size, 1024) | |
173 | self.assertEqual(params.dict_id, 0) |
|
186 | self.assertEqual(params.dict_id, 0) | |
174 | self.assertFalse(params.has_checksum) |
|
187 | self.assertFalse(params.has_checksum) | |
175 |
|
188 | |||
176 | # Lowest 2 bits indicate a dictionary and length. Here, the dict id is 1 byte. |
|
189 | # Lowest 2 bits indicate a dictionary and length. Here, the dict id is 1 byte. | |
177 |
params = zstd.get_frame_parameters(zstd.FRAME_HEADER + b |
|
190 | params = zstd.get_frame_parameters(zstd.FRAME_HEADER + b"\x01\x00\xff") | |
178 | self.assertEqual(params.content_size, zstd.CONTENTSIZE_UNKNOWN) |
|
191 | self.assertEqual(params.content_size, zstd.CONTENTSIZE_UNKNOWN) | |
179 | self.assertEqual(params.window_size, 1024) |
|
192 | self.assertEqual(params.window_size, 1024) | |
180 | self.assertEqual(params.dict_id, 255) |
|
193 | self.assertEqual(params.dict_id, 255) | |
181 | self.assertFalse(params.has_checksum) |
|
194 | self.assertFalse(params.has_checksum) | |
182 |
|
195 | |||
183 | # Lowest 3rd bit indicates if checksum is present. |
|
196 | # Lowest 3rd bit indicates if checksum is present. | |
184 |
params = zstd.get_frame_parameters(zstd.FRAME_HEADER + b |
|
197 | params = zstd.get_frame_parameters(zstd.FRAME_HEADER + b"\x04\x00") | |
185 | self.assertEqual(params.content_size, zstd.CONTENTSIZE_UNKNOWN) |
|
198 | self.assertEqual(params.content_size, zstd.CONTENTSIZE_UNKNOWN) | |
186 | self.assertEqual(params.window_size, 1024) |
|
199 | self.assertEqual(params.window_size, 1024) | |
187 | self.assertEqual(params.dict_id, 0) |
|
200 | self.assertEqual(params.dict_id, 0) | |
188 | self.assertTrue(params.has_checksum) |
|
201 | self.assertTrue(params.has_checksum) | |
189 |
|
202 | |||
190 | # Upper 2 bits indicate content size. |
|
203 | # Upper 2 bits indicate content size. | |
191 |
params = zstd.get_frame_parameters(zstd.FRAME_HEADER + b |
|
204 | params = zstd.get_frame_parameters(zstd.FRAME_HEADER + b"\x40\x00\xff\x00") | |
192 | self.assertEqual(params.content_size, 511) |
|
205 | self.assertEqual(params.content_size, 511) | |
193 | self.assertEqual(params.window_size, 1024) |
|
206 | self.assertEqual(params.window_size, 1024) | |
194 | self.assertEqual(params.dict_id, 0) |
|
207 | self.assertEqual(params.dict_id, 0) | |
195 | self.assertFalse(params.has_checksum) |
|
208 | self.assertFalse(params.has_checksum) | |
196 |
|
209 | |||
197 | # Window descriptor is 2nd byte after frame header. |
|
210 | # Window descriptor is 2nd byte after frame header. | |
198 |
params = zstd.get_frame_parameters(zstd.FRAME_HEADER + b |
|
211 | params = zstd.get_frame_parameters(zstd.FRAME_HEADER + b"\x00\x40") | |
199 | self.assertEqual(params.content_size, zstd.CONTENTSIZE_UNKNOWN) |
|
212 | self.assertEqual(params.content_size, zstd.CONTENTSIZE_UNKNOWN) | |
200 | self.assertEqual(params.window_size, 262144) |
|
213 | self.assertEqual(params.window_size, 262144) | |
201 | self.assertEqual(params.dict_id, 0) |
|
214 | self.assertEqual(params.dict_id, 0) | |
202 | self.assertFalse(params.has_checksum) |
|
215 | self.assertFalse(params.has_checksum) | |
203 |
|
216 | |||
204 | # Set multiple things. |
|
217 | # Set multiple things. | |
205 |
params = zstd.get_frame_parameters(zstd.FRAME_HEADER + b |
|
218 | params = zstd.get_frame_parameters(zstd.FRAME_HEADER + b"\x45\x40\x0f\x10\x00") | |
206 | self.assertEqual(params.content_size, 272) |
|
219 | self.assertEqual(params.content_size, 272) | |
207 | self.assertEqual(params.window_size, 262144) |
|
220 | self.assertEqual(params.window_size, 262144) | |
208 | self.assertEqual(params.dict_id, 15) |
|
221 | self.assertEqual(params.dict_id, 15) | |
209 | self.assertTrue(params.has_checksum) |
|
222 | self.assertTrue(params.has_checksum) | |
210 |
|
223 | |||
211 | def test_input_types(self): |
|
224 | def test_input_types(self): | |
212 |
v = zstd.FRAME_HEADER + b |
|
225 | v = zstd.FRAME_HEADER + b"\x00\x00" | |
213 |
|
226 | |||
214 | mutable_array = bytearray(len(v)) |
|
227 | mutable_array = bytearray(len(v)) | |
215 | mutable_array[:] = v |
|
228 | mutable_array[:] = v |
@@ -7,70 +7,99 b' try:' | |||||
7 | import hypothesis |
|
7 | import hypothesis | |
8 | import hypothesis.strategies as strategies |
|
8 | import hypothesis.strategies as strategies | |
9 | except ImportError: |
|
9 | except ImportError: | |
10 |
raise unittest.SkipTest( |
|
10 | raise unittest.SkipTest("hypothesis not available") | |
11 |
|
11 | |||
12 | import zstandard as zstd |
|
12 | import zstandard as zstd | |
13 |
|
13 | |||
14 | from .common import ( |
|
14 | from .common import ( | |
15 | make_cffi, |
|
15 | make_cffi, | |
|
16 | TestCase, | |||
|
17 | ) | |||
|
18 | ||||
|
19 | ||||
|
20 | s_windowlog = strategies.integers( | |||
|
21 | min_value=zstd.WINDOWLOG_MIN, max_value=zstd.WINDOWLOG_MAX | |||
|
22 | ) | |||
|
23 | s_chainlog = strategies.integers( | |||
|
24 | min_value=zstd.CHAINLOG_MIN, max_value=zstd.CHAINLOG_MAX | |||
|
25 | ) | |||
|
26 | s_hashlog = strategies.integers(min_value=zstd.HASHLOG_MIN, max_value=zstd.HASHLOG_MAX) | |||
|
27 | s_searchlog = strategies.integers( | |||
|
28 | min_value=zstd.SEARCHLOG_MIN, max_value=zstd.SEARCHLOG_MAX | |||
|
29 | ) | |||
|
30 | s_minmatch = strategies.integers( | |||
|
31 | min_value=zstd.MINMATCH_MIN, max_value=zstd.MINMATCH_MAX | |||
|
32 | ) | |||
|
33 | s_targetlength = strategies.integers( | |||
|
34 | min_value=zstd.TARGETLENGTH_MIN, max_value=zstd.TARGETLENGTH_MAX | |||
|
35 | ) | |||
|
36 | s_strategy = strategies.sampled_from( | |||
|
37 | ( | |||
|
38 | zstd.STRATEGY_FAST, | |||
|
39 | zstd.STRATEGY_DFAST, | |||
|
40 | zstd.STRATEGY_GREEDY, | |||
|
41 | zstd.STRATEGY_LAZY, | |||
|
42 | zstd.STRATEGY_LAZY2, | |||
|
43 | zstd.STRATEGY_BTLAZY2, | |||
|
44 | zstd.STRATEGY_BTOPT, | |||
|
45 | zstd.STRATEGY_BTULTRA, | |||
|
46 | zstd.STRATEGY_BTULTRA2, | |||
|
47 | ) | |||
16 | ) |
|
48 | ) | |
17 |
|
49 | |||
18 |
|
50 | |||
19 | s_windowlog = strategies.integers(min_value=zstd.WINDOWLOG_MIN, |
|
51 | @make_cffi | |
20 | max_value=zstd.WINDOWLOG_MAX) |
|
52 | @unittest.skipUnless("ZSTD_SLOW_TESTS" in os.environ, "ZSTD_SLOW_TESTS not set") | |
21 | s_chainlog = strategies.integers(min_value=zstd.CHAINLOG_MIN, |
|
53 | class TestCompressionParametersHypothesis(TestCase): | |
22 | max_value=zstd.CHAINLOG_MAX) |
|
54 | @hypothesis.given( | |
23 | s_hashlog = strategies.integers(min_value=zstd.HASHLOG_MIN, |
|
55 | s_windowlog, | |
24 | max_value=zstd.HASHLOG_MAX) |
|
56 | s_chainlog, | |
25 | s_searchlog = strategies.integers(min_value=zstd.SEARCHLOG_MIN, |
|
57 | s_hashlog, | |
26 | max_value=zstd.SEARCHLOG_MAX) |
|
58 | s_searchlog, | |
27 | s_minmatch = strategies.integers(min_value=zstd.MINMATCH_MIN, |
|
59 | s_minmatch, | |
28 | max_value=zstd.MINMATCH_MAX) |
|
60 | s_targetlength, | |
29 | s_targetlength = strategies.integers(min_value=zstd.TARGETLENGTH_MIN, |
|
61 | s_strategy, | |
30 | max_value=zstd.TARGETLENGTH_MAX) |
|
62 | ) | |
31 | s_strategy = strategies.sampled_from((zstd.STRATEGY_FAST, |
|
63 | def test_valid_init( | |
32 | zstd.STRATEGY_DFAST, |
|
64 | self, windowlog, chainlog, hashlog, searchlog, minmatch, targetlength, strategy | |
33 | zstd.STRATEGY_GREEDY, |
|
65 | ): | |
34 | zstd.STRATEGY_LAZY, |
|
66 | zstd.ZstdCompressionParameters( | |
35 | zstd.STRATEGY_LAZY2, |
|
67 | window_log=windowlog, | |
36 | zstd.STRATEGY_BTLAZY2, |
|
68 | chain_log=chainlog, | |
37 | zstd.STRATEGY_BTOPT, |
|
69 | hash_log=hashlog, | |
38 | zstd.STRATEGY_BTULTRA, |
|
70 | search_log=searchlog, | |
39 | zstd.STRATEGY_BTULTRA2)) |
|
71 | min_match=minmatch, | |
40 |
|
72 | target_length=targetlength, | ||
|
73 | strategy=strategy, | |||
|
74 | ) | |||
41 |
|
75 | |||
42 | @make_cffi |
|
76 | @hypothesis.given( | |
43 | @unittest.skipUnless('ZSTD_SLOW_TESTS' in os.environ, 'ZSTD_SLOW_TESTS not set') |
|
77 | s_windowlog, | |
44 | class TestCompressionParametersHypothesis(unittest.TestCase): |
|
78 | s_chainlog, | |
45 | @hypothesis.given(s_windowlog, s_chainlog, s_hashlog, s_searchlog, |
|
79 | s_hashlog, | |
46 | s_minmatch, s_targetlength, s_strategy) |
|
80 | s_searchlog, | |
47 | def test_valid_init(self, windowlog, chainlog, hashlog, searchlog, |
|
81 | s_minmatch, | |
48 | minmatch, targetlength, strategy): |
|
82 | s_targetlength, | |
49 | zstd.ZstdCompressionParameters(window_log=windowlog, |
|
83 | s_strategy, | |
50 | chain_log=chainlog, |
|
84 | ) | |
51 | hash_log=hashlog, |
|
85 | def test_estimated_compression_context_size( | |
52 | search_log=searchlog, |
|
86 | self, windowlog, chainlog, hashlog, searchlog, minmatch, targetlength, strategy | |
53 | min_match=minmatch, |
|
87 | ): | |
54 | target_length=targetlength, |
|
88 | if minmatch == zstd.MINMATCH_MIN and strategy in ( | |
55 | strategy=strategy) |
|
89 | zstd.STRATEGY_FAST, | |
56 |
|
90 | zstd.STRATEGY_GREEDY, | ||
57 | @hypothesis.given(s_windowlog, s_chainlog, s_hashlog, s_searchlog, |
|
91 | ): | |
58 | s_minmatch, s_targetlength, s_strategy) |
|
|||
59 | def test_estimated_compression_context_size(self, windowlog, chainlog, |
|
|||
60 | hashlog, searchlog, |
|
|||
61 | minmatch, targetlength, |
|
|||
62 | strategy): |
|
|||
63 | if minmatch == zstd.MINMATCH_MIN and strategy in (zstd.STRATEGY_FAST, zstd.STRATEGY_GREEDY): |
|
|||
64 | minmatch += 1 |
|
92 | minmatch += 1 | |
65 | elif minmatch == zstd.MINMATCH_MAX and strategy != zstd.STRATEGY_FAST: |
|
93 | elif minmatch == zstd.MINMATCH_MAX and strategy != zstd.STRATEGY_FAST: | |
66 | minmatch -= 1 |
|
94 | minmatch -= 1 | |
67 |
|
95 | |||
68 |
p = zstd.ZstdCompressionParameters( |
|
96 | p = zstd.ZstdCompressionParameters( | |
69 | chain_log=chainlog, |
|
97 | window_log=windowlog, | |
70 | hash_log=hashlog, |
|
98 | chain_log=chainlog, | |
71 | search_log=searchlog, |
|
99 | hash_log=hashlog, | |
72 | min_match=minmatch, |
|
100 | search_log=searchlog, | |
73 | target_length=targetlength, |
|
101 | min_match=minmatch, | |
74 | strategy=strategy) |
|
102 | target_length=targetlength, | |
|
103 | strategy=strategy, | |||
|
104 | ) | |||
75 | size = p.estimated_compression_context_size() |
|
105 | size = p.estimated_compression_context_size() | |
76 |
|
This diff has been collapsed as it changes many lines, (729 lines changed) Show them Hide them | |||||
@@ -13,6 +13,7 b' from .common import (' | |||||
13 | make_cffi, |
|
13 | make_cffi, | |
14 | NonClosingBytesIO, |
|
14 | NonClosingBytesIO, | |
15 | OpCountingBytesIO, |
|
15 | OpCountingBytesIO, | |
|
16 | TestCase, | |||
16 | ) |
|
17 | ) | |
17 |
|
18 | |||
18 |
|
19 | |||
@@ -23,62 +24,67 b' else:' | |||||
23 |
|
24 | |||
24 |
|
25 | |||
25 | @make_cffi |
|
26 | @make_cffi | |
26 |
class TestFrameHeaderSize( |
|
27 | class TestFrameHeaderSize(TestCase): | |
27 | def test_empty(self): |
|
28 | def test_empty(self): | |
28 |
with self.assertRaisesRegex |
|
29 | with self.assertRaisesRegex( | |
29 | zstd.ZstdError, 'could not determine frame header size: Src size ' |
|
30 | zstd.ZstdError, | |
30 | 'is incorrect'): |
|
31 | "could not determine frame header size: Src size " "is incorrect", | |
31 | zstd.frame_header_size(b'') |
|
32 | ): | |
|
33 | zstd.frame_header_size(b"") | |||
32 |
|
34 | |||
33 | def test_too_small(self): |
|
35 | def test_too_small(self): | |
34 |
with self.assertRaisesRegex |
|
36 | with self.assertRaisesRegex( | |
35 | zstd.ZstdError, 'could not determine frame header size: Src size ' |
|
37 | zstd.ZstdError, | |
36 | 'is incorrect'): |
|
38 | "could not determine frame header size: Src size " "is incorrect", | |
37 | zstd.frame_header_size(b'foob') |
|
39 | ): | |
|
40 | zstd.frame_header_size(b"foob") | |||
38 |
|
41 | |||
39 | def test_basic(self): |
|
42 | def test_basic(self): | |
40 | # It doesn't matter that it isn't a valid frame. |
|
43 | # It doesn't matter that it isn't a valid frame. | |
41 |
self.assertEqual(zstd.frame_header_size(b |
|
44 | self.assertEqual(zstd.frame_header_size(b"long enough but no magic"), 6) | |
42 |
|
45 | |||
43 |
|
46 | |||
44 | @make_cffi |
|
47 | @make_cffi | |
45 |
class TestFrameContentSize( |
|
48 | class TestFrameContentSize(TestCase): | |
46 | def test_empty(self): |
|
49 | def test_empty(self): | |
47 |
with self.assertRaisesRegex |
|
50 | with self.assertRaisesRegex( | |
48 |
|
|
51 | zstd.ZstdError, "error when determining content size" | |
49 | zstd.frame_content_size(b'') |
|
52 | ): | |
|
53 | zstd.frame_content_size(b"") | |||
50 |
|
54 | |||
51 | def test_too_small(self): |
|
55 | def test_too_small(self): | |
52 |
with self.assertRaisesRegex |
|
56 | with self.assertRaisesRegex( | |
53 |
|
|
57 | zstd.ZstdError, "error when determining content size" | |
54 | zstd.frame_content_size(b'foob') |
|
58 | ): | |
|
59 | zstd.frame_content_size(b"foob") | |||
55 |
|
60 | |||
56 | def test_bad_frame(self): |
|
61 | def test_bad_frame(self): | |
57 |
with self.assertRaisesRegex |
|
62 | with self.assertRaisesRegex( | |
58 |
|
|
63 | zstd.ZstdError, "error when determining content size" | |
59 | zstd.frame_content_size(b'invalid frame header') |
|
64 | ): | |
|
65 | zstd.frame_content_size(b"invalid frame header") | |||
60 |
|
66 | |||
61 | def test_unknown(self): |
|
67 | def test_unknown(self): | |
62 | cctx = zstd.ZstdCompressor(write_content_size=False) |
|
68 | cctx = zstd.ZstdCompressor(write_content_size=False) | |
63 |
frame = cctx.compress(b |
|
69 | frame = cctx.compress(b"foobar") | |
64 |
|
70 | |||
65 | self.assertEqual(zstd.frame_content_size(frame), -1) |
|
71 | self.assertEqual(zstd.frame_content_size(frame), -1) | |
66 |
|
72 | |||
67 | def test_empty(self): |
|
73 | def test_empty(self): | |
68 | cctx = zstd.ZstdCompressor() |
|
74 | cctx = zstd.ZstdCompressor() | |
69 |
frame = cctx.compress(b |
|
75 | frame = cctx.compress(b"") | |
70 |
|
76 | |||
71 | self.assertEqual(zstd.frame_content_size(frame), 0) |
|
77 | self.assertEqual(zstd.frame_content_size(frame), 0) | |
72 |
|
78 | |||
73 | def test_basic(self): |
|
79 | def test_basic(self): | |
74 | cctx = zstd.ZstdCompressor() |
|
80 | cctx = zstd.ZstdCompressor() | |
75 |
frame = cctx.compress(b |
|
81 | frame = cctx.compress(b"foobar") | |
76 |
|
82 | |||
77 | self.assertEqual(zstd.frame_content_size(frame), 6) |
|
83 | self.assertEqual(zstd.frame_content_size(frame), 6) | |
78 |
|
84 | |||
79 |
|
85 | |||
80 | @make_cffi |
|
86 | @make_cffi | |
81 |
class TestDecompressor( |
|
87 | class TestDecompressor(TestCase): | |
82 | def test_memory_size(self): |
|
88 | def test_memory_size(self): | |
83 | dctx = zstd.ZstdDecompressor() |
|
89 | dctx = zstd.ZstdDecompressor() | |
84 |
|
90 | |||
@@ -86,22 +92,26 b' class TestDecompressor(unittest.TestCase' | |||||
86 |
|
92 | |||
87 |
|
93 | |||
88 | @make_cffi |
|
94 | @make_cffi | |
89 |
class TestDecompressor_decompress( |
|
95 | class TestDecompressor_decompress(TestCase): | |
90 | def test_empty_input(self): |
|
96 | def test_empty_input(self): | |
91 | dctx = zstd.ZstdDecompressor() |
|
97 | dctx = zstd.ZstdDecompressor() | |
92 |
|
98 | |||
93 | with self.assertRaisesRegexp(zstd.ZstdError, 'error determining content size from frame header'): |
|
99 | with self.assertRaisesRegex( | |
94 | dctx.decompress(b'') |
|
100 | zstd.ZstdError, "error determining content size from frame header" | |
|
101 | ): | |||
|
102 | dctx.decompress(b"") | |||
95 |
|
103 | |||
96 | def test_invalid_input(self): |
|
104 | def test_invalid_input(self): | |
97 | dctx = zstd.ZstdDecompressor() |
|
105 | dctx = zstd.ZstdDecompressor() | |
98 |
|
106 | |||
99 | with self.assertRaisesRegexp(zstd.ZstdError, 'error determining content size from frame header'): |
|
107 | with self.assertRaisesRegex( | |
100 | dctx.decompress(b'foobar') |
|
108 | zstd.ZstdError, "error determining content size from frame header" | |
|
109 | ): | |||
|
110 | dctx.decompress(b"foobar") | |||
101 |
|
111 | |||
102 | def test_input_types(self): |
|
112 | def test_input_types(self): | |
103 | cctx = zstd.ZstdCompressor(level=1) |
|
113 | cctx = zstd.ZstdCompressor(level=1) | |
104 |
compressed = cctx.compress(b |
|
114 | compressed = cctx.compress(b"foo") | |
105 |
|
115 | |||
106 | mutable_array = bytearray(len(compressed)) |
|
116 | mutable_array = bytearray(len(compressed)) | |
107 | mutable_array[:] = compressed |
|
117 | mutable_array[:] = compressed | |
@@ -114,36 +124,38 b' class TestDecompressor_decompress(unitte' | |||||
114 |
|
124 | |||
115 | dctx = zstd.ZstdDecompressor() |
|
125 | dctx = zstd.ZstdDecompressor() | |
116 | for source in sources: |
|
126 | for source in sources: | |
117 |
self.assertEqual(dctx.decompress(source), b |
|
127 | self.assertEqual(dctx.decompress(source), b"foo") | |
118 |
|
128 | |||
119 | def test_no_content_size_in_frame(self): |
|
129 | def test_no_content_size_in_frame(self): | |
120 | cctx = zstd.ZstdCompressor(write_content_size=False) |
|
130 | cctx = zstd.ZstdCompressor(write_content_size=False) | |
121 |
compressed = cctx.compress(b |
|
131 | compressed = cctx.compress(b"foobar") | |
122 |
|
132 | |||
123 | dctx = zstd.ZstdDecompressor() |
|
133 | dctx = zstd.ZstdDecompressor() | |
124 | with self.assertRaisesRegexp(zstd.ZstdError, 'could not determine content size in frame header'): |
|
134 | with self.assertRaisesRegex( | |
|
135 | zstd.ZstdError, "could not determine content size in frame header" | |||
|
136 | ): | |||
125 | dctx.decompress(compressed) |
|
137 | dctx.decompress(compressed) | |
126 |
|
138 | |||
127 | def test_content_size_present(self): |
|
139 | def test_content_size_present(self): | |
128 | cctx = zstd.ZstdCompressor() |
|
140 | cctx = zstd.ZstdCompressor() | |
129 |
compressed = cctx.compress(b |
|
141 | compressed = cctx.compress(b"foobar") | |
130 |
|
142 | |||
131 | dctx = zstd.ZstdDecompressor() |
|
143 | dctx = zstd.ZstdDecompressor() | |
132 | decompressed = dctx.decompress(compressed) |
|
144 | decompressed = dctx.decompress(compressed) | |
133 |
self.assertEqual(decompressed, b |
|
145 | self.assertEqual(decompressed, b"foobar") | |
134 |
|
146 | |||
135 | def test_empty_roundtrip(self): |
|
147 | def test_empty_roundtrip(self): | |
136 | cctx = zstd.ZstdCompressor() |
|
148 | cctx = zstd.ZstdCompressor() | |
137 |
compressed = cctx.compress(b |
|
149 | compressed = cctx.compress(b"") | |
138 |
|
150 | |||
139 | dctx = zstd.ZstdDecompressor() |
|
151 | dctx = zstd.ZstdDecompressor() | |
140 | decompressed = dctx.decompress(compressed) |
|
152 | decompressed = dctx.decompress(compressed) | |
141 |
|
153 | |||
142 |
self.assertEqual(decompressed, b |
|
154 | self.assertEqual(decompressed, b"") | |
143 |
|
155 | |||
144 | def test_max_output_size(self): |
|
156 | def test_max_output_size(self): | |
145 | cctx = zstd.ZstdCompressor(write_content_size=False) |
|
157 | cctx = zstd.ZstdCompressor(write_content_size=False) | |
146 |
source = b |
|
158 | source = b"foobar" * 256 | |
147 | compressed = cctx.compress(source) |
|
159 | compressed = cctx.compress(source) | |
148 |
|
160 | |||
149 | dctx = zstd.ZstdDecompressor() |
|
161 | dctx = zstd.ZstdDecompressor() | |
@@ -152,8 +164,9 b' class TestDecompressor_decompress(unitte' | |||||
152 | self.assertEqual(decompressed, source) |
|
164 | self.assertEqual(decompressed, source) | |
153 |
|
165 | |||
154 | # Input size - 1 fails |
|
166 | # Input size - 1 fails | |
155 |
with self.assertRaisesRegex |
|
167 | with self.assertRaisesRegex( | |
156 |
|
|
168 | zstd.ZstdError, "decompression error: did not decompress full frame" | |
|
169 | ): | |||
157 | dctx.decompress(compressed, max_output_size=len(source) - 1) |
|
170 | dctx.decompress(compressed, max_output_size=len(source) - 1) | |
158 |
|
171 | |||
159 | # Input size + 1 works |
|
172 | # Input size + 1 works | |
@@ -166,24 +179,24 b' class TestDecompressor_decompress(unitte' | |||||
166 |
|
179 | |||
167 | def test_stupidly_large_output_buffer(self): |
|
180 | def test_stupidly_large_output_buffer(self): | |
168 | cctx = zstd.ZstdCompressor(write_content_size=False) |
|
181 | cctx = zstd.ZstdCompressor(write_content_size=False) | |
169 |
compressed = cctx.compress(b |
|
182 | compressed = cctx.compress(b"foobar" * 256) | |
170 | dctx = zstd.ZstdDecompressor() |
|
183 | dctx = zstd.ZstdDecompressor() | |
171 |
|
184 | |||
172 | # Will get OverflowError on some Python distributions that can't |
|
185 | # Will get OverflowError on some Python distributions that can't | |
173 | # handle really large integers. |
|
186 | # handle really large integers. | |
174 | with self.assertRaises((MemoryError, OverflowError)): |
|
187 | with self.assertRaises((MemoryError, OverflowError)): | |
175 | dctx.decompress(compressed, max_output_size=2**62) |
|
188 | dctx.decompress(compressed, max_output_size=2 ** 62) | |
176 |
|
189 | |||
177 | def test_dictionary(self): |
|
190 | def test_dictionary(self): | |
178 | samples = [] |
|
191 | samples = [] | |
179 | for i in range(128): |
|
192 | for i in range(128): | |
180 |
samples.append(b |
|
193 | samples.append(b"foo" * 64) | |
181 |
samples.append(b |
|
194 | samples.append(b"bar" * 64) | |
182 |
samples.append(b |
|
195 | samples.append(b"foobar" * 64) | |
183 |
|
196 | |||
184 | d = zstd.train_dictionary(8192, samples) |
|
197 | d = zstd.train_dictionary(8192, samples) | |
185 |
|
198 | |||
186 |
orig = b |
|
199 | orig = b"foobar" * 16384 | |
187 | cctx = zstd.ZstdCompressor(level=1, dict_data=d) |
|
200 | cctx = zstd.ZstdCompressor(level=1, dict_data=d) | |
188 | compressed = cctx.compress(orig) |
|
201 | compressed = cctx.compress(orig) | |
189 |
|
202 | |||
@@ -195,13 +208,13 b' class TestDecompressor_decompress(unitte' | |||||
195 | def test_dictionary_multiple(self): |
|
208 | def test_dictionary_multiple(self): | |
196 | samples = [] |
|
209 | samples = [] | |
197 | for i in range(128): |
|
210 | for i in range(128): | |
198 |
samples.append(b |
|
211 | samples.append(b"foo" * 64) | |
199 |
samples.append(b |
|
212 | samples.append(b"bar" * 64) | |
200 |
samples.append(b |
|
213 | samples.append(b"foobar" * 64) | |
201 |
|
214 | |||
202 | d = zstd.train_dictionary(8192, samples) |
|
215 | d = zstd.train_dictionary(8192, samples) | |
203 |
|
216 | |||
204 |
sources = (b |
|
217 | sources = (b"foobar" * 8192, b"foo" * 8192, b"bar" * 8192) | |
205 | compressed = [] |
|
218 | compressed = [] | |
206 | cctx = zstd.ZstdCompressor(level=1, dict_data=d) |
|
219 | cctx = zstd.ZstdCompressor(level=1, dict_data=d) | |
207 | for source in sources: |
|
220 | for source in sources: | |
@@ -213,7 +226,7 b' class TestDecompressor_decompress(unitte' | |||||
213 | self.assertEqual(decompressed, sources[i]) |
|
226 | self.assertEqual(decompressed, sources[i]) | |
214 |
|
227 | |||
215 | def test_max_window_size(self): |
|
228 | def test_max_window_size(self): | |
216 |
with open(__file__, |
|
229 | with open(__file__, "rb") as fh: | |
217 | source = fh.read() |
|
230 | source = fh.read() | |
218 |
|
231 | |||
219 | # If we write a content size, the decompressor engages single pass |
|
232 | # If we write a content size, the decompressor engages single pass | |
@@ -221,15 +234,16 b' class TestDecompressor_decompress(unitte' | |||||
221 | cctx = zstd.ZstdCompressor(write_content_size=False) |
|
234 | cctx = zstd.ZstdCompressor(write_content_size=False) | |
222 | frame = cctx.compress(source) |
|
235 | frame = cctx.compress(source) | |
223 |
|
236 | |||
224 | dctx = zstd.ZstdDecompressor(max_window_size=2**zstd.WINDOWLOG_MIN) |
|
237 | dctx = zstd.ZstdDecompressor(max_window_size=2 ** zstd.WINDOWLOG_MIN) | |
225 |
|
238 | |||
226 |
with self.assertRaisesRegex |
|
239 | with self.assertRaisesRegex( | |
227 |
zstd.ZstdError, |
|
240 | zstd.ZstdError, "decompression error: Frame requires too much memory" | |
|
241 | ): | |||
228 | dctx.decompress(frame, max_output_size=len(source)) |
|
242 | dctx.decompress(frame, max_output_size=len(source)) | |
229 |
|
243 | |||
230 |
|
244 | |||
231 | @make_cffi |
|
245 | @make_cffi | |
232 |
class TestDecompressor_copy_stream( |
|
246 | class TestDecompressor_copy_stream(TestCase): | |
233 | def test_no_read(self): |
|
247 | def test_no_read(self): | |
234 | source = object() |
|
248 | source = object() | |
235 | dest = io.BytesIO() |
|
249 | dest = io.BytesIO() | |
@@ -256,12 +270,12 b' class TestDecompressor_copy_stream(unitt' | |||||
256 |
|
270 | |||
257 | self.assertEqual(r, 0) |
|
271 | self.assertEqual(r, 0) | |
258 | self.assertEqual(w, 0) |
|
272 | self.assertEqual(w, 0) | |
259 |
self.assertEqual(dest.getvalue(), b |
|
273 | self.assertEqual(dest.getvalue(), b"") | |
260 |
|
274 | |||
261 | def test_large_data(self): |
|
275 | def test_large_data(self): | |
262 | source = io.BytesIO() |
|
276 | source = io.BytesIO() | |
263 | for i in range(255): |
|
277 | for i in range(255): | |
264 |
source.write(struct.Struct( |
|
278 | source.write(struct.Struct(">B").pack(i) * 16384) | |
265 | source.seek(0) |
|
279 | source.seek(0) | |
266 |
|
280 | |||
267 | compressed = io.BytesIO() |
|
281 | compressed = io.BytesIO() | |
@@ -277,33 +291,32 b' class TestDecompressor_copy_stream(unitt' | |||||
277 | self.assertEqual(w, len(source.getvalue())) |
|
291 | self.assertEqual(w, len(source.getvalue())) | |
278 |
|
292 | |||
279 | def test_read_write_size(self): |
|
293 | def test_read_write_size(self): | |
280 | source = OpCountingBytesIO(zstd.ZstdCompressor().compress( |
|
294 | source = OpCountingBytesIO(zstd.ZstdCompressor().compress(b"foobarfoobar")) | |
281 | b'foobarfoobar')) |
|
|||
282 |
|
295 | |||
283 | dest = OpCountingBytesIO() |
|
296 | dest = OpCountingBytesIO() | |
284 | dctx = zstd.ZstdDecompressor() |
|
297 | dctx = zstd.ZstdDecompressor() | |
285 | r, w = dctx.copy_stream(source, dest, read_size=1, write_size=1) |
|
298 | r, w = dctx.copy_stream(source, dest, read_size=1, write_size=1) | |
286 |
|
299 | |||
287 | self.assertEqual(r, len(source.getvalue())) |
|
300 | self.assertEqual(r, len(source.getvalue())) | |
288 |
self.assertEqual(w, len(b |
|
301 | self.assertEqual(w, len(b"foobarfoobar")) | |
289 | self.assertEqual(source._read_count, len(source.getvalue()) + 1) |
|
302 | self.assertEqual(source._read_count, len(source.getvalue()) + 1) | |
290 | self.assertEqual(dest._write_count, len(dest.getvalue())) |
|
303 | self.assertEqual(dest._write_count, len(dest.getvalue())) | |
291 |
|
304 | |||
292 |
|
305 | |||
293 | @make_cffi |
|
306 | @make_cffi | |
294 |
class TestDecompressor_stream_reader( |
|
307 | class TestDecompressor_stream_reader(TestCase): | |
295 | def test_context_manager(self): |
|
308 | def test_context_manager(self): | |
296 | dctx = zstd.ZstdDecompressor() |
|
309 | dctx = zstd.ZstdDecompressor() | |
297 |
|
310 | |||
298 |
with dctx.stream_reader(b |
|
311 | with dctx.stream_reader(b"foo") as reader: | |
299 |
with self.assertRaisesRegex |
|
312 | with self.assertRaisesRegex(ValueError, "cannot __enter__ multiple times"): | |
300 | with reader as reader2: |
|
313 | with reader as reader2: | |
301 | pass |
|
314 | pass | |
302 |
|
315 | |||
303 | def test_not_implemented(self): |
|
316 | def test_not_implemented(self): | |
304 | dctx = zstd.ZstdDecompressor() |
|
317 | dctx = zstd.ZstdDecompressor() | |
305 |
|
318 | |||
306 |
with dctx.stream_reader(b |
|
319 | with dctx.stream_reader(b"foo") as reader: | |
307 | with self.assertRaises(io.UnsupportedOperation): |
|
320 | with self.assertRaises(io.UnsupportedOperation): | |
308 | reader.readline() |
|
321 | reader.readline() | |
309 |
|
322 | |||
@@ -317,7 +330,7 b' class TestDecompressor_stream_reader(uni' | |||||
317 | next(reader) |
|
330 | next(reader) | |
318 |
|
331 | |||
319 | with self.assertRaises(io.UnsupportedOperation): |
|
332 | with self.assertRaises(io.UnsupportedOperation): | |
320 |
reader.write(b |
|
333 | reader.write(b"foo") | |
321 |
|
334 | |||
322 | with self.assertRaises(io.UnsupportedOperation): |
|
335 | with self.assertRaises(io.UnsupportedOperation): | |
323 | reader.writelines([]) |
|
336 | reader.writelines([]) | |
@@ -325,7 +338,7 b' class TestDecompressor_stream_reader(uni' | |||||
325 | def test_constant_methods(self): |
|
338 | def test_constant_methods(self): | |
326 | dctx = zstd.ZstdDecompressor() |
|
339 | dctx = zstd.ZstdDecompressor() | |
327 |
|
340 | |||
328 |
with dctx.stream_reader(b |
|
341 | with dctx.stream_reader(b"foo") as reader: | |
329 | self.assertFalse(reader.closed) |
|
342 | self.assertFalse(reader.closed) | |
330 | self.assertTrue(reader.readable()) |
|
343 | self.assertTrue(reader.readable()) | |
331 | self.assertFalse(reader.writable()) |
|
344 | self.assertFalse(reader.writable()) | |
@@ -340,29 +353,31 b' class TestDecompressor_stream_reader(uni' | |||||
340 | def test_read_closed(self): |
|
353 | def test_read_closed(self): | |
341 | dctx = zstd.ZstdDecompressor() |
|
354 | dctx = zstd.ZstdDecompressor() | |
342 |
|
355 | |||
343 |
with dctx.stream_reader(b |
|
356 | with dctx.stream_reader(b"foo") as reader: | |
344 | reader.close() |
|
357 | reader.close() | |
345 | self.assertTrue(reader.closed) |
|
358 | self.assertTrue(reader.closed) | |
346 |
with self.assertRaisesRegex |
|
359 | with self.assertRaisesRegex(ValueError, "stream is closed"): | |
347 | reader.read(1) |
|
360 | reader.read(1) | |
348 |
|
361 | |||
349 | def test_read_sizes(self): |
|
362 | def test_read_sizes(self): | |
350 | cctx = zstd.ZstdCompressor() |
|
363 | cctx = zstd.ZstdCompressor() | |
351 |
foo = cctx.compress(b |
|
364 | foo = cctx.compress(b"foo") | |
352 |
|
365 | |||
353 | dctx = zstd.ZstdDecompressor() |
|
366 | dctx = zstd.ZstdDecompressor() | |
354 |
|
367 | |||
355 | with dctx.stream_reader(foo) as reader: |
|
368 | with dctx.stream_reader(foo) as reader: | |
356 | with self.assertRaisesRegexp(ValueError, 'cannot read negative amounts less than -1'): |
|
369 | with self.assertRaisesRegex( | |
|
370 | ValueError, "cannot read negative amounts less than -1" | |||
|
371 | ): | |||
357 | reader.read(-2) |
|
372 | reader.read(-2) | |
358 |
|
373 | |||
359 |
self.assertEqual(reader.read(0), b |
|
374 | self.assertEqual(reader.read(0), b"") | |
360 |
self.assertEqual(reader.read(), b |
|
375 | self.assertEqual(reader.read(), b"foo") | |
361 |
|
376 | |||
362 | def test_read_buffer(self): |
|
377 | def test_read_buffer(self): | |
363 | cctx = zstd.ZstdCompressor() |
|
378 | cctx = zstd.ZstdCompressor() | |
364 |
|
379 | |||
365 |
source = b |
|
380 | source = b"".join([b"foo" * 60, b"bar" * 60, b"baz" * 60]) | |
366 | frame = cctx.compress(source) |
|
381 | frame = cctx.compress(source) | |
367 |
|
382 | |||
368 | dctx = zstd.ZstdDecompressor() |
|
383 | dctx = zstd.ZstdDecompressor() | |
@@ -376,14 +391,14 b' class TestDecompressor_stream_reader(uni' | |||||
376 | self.assertEqual(reader.tell(), len(source)) |
|
391 | self.assertEqual(reader.tell(), len(source)) | |
377 |
|
392 | |||
378 | # Read after EOF should return empty bytes. |
|
393 | # Read after EOF should return empty bytes. | |
379 |
self.assertEqual(reader.read(1), b |
|
394 | self.assertEqual(reader.read(1), b"") | |
380 | self.assertEqual(reader.tell(), len(result)) |
|
395 | self.assertEqual(reader.tell(), len(result)) | |
381 |
|
396 | |||
382 | self.assertTrue(reader.closed) |
|
397 | self.assertTrue(reader.closed) | |
383 |
|
398 | |||
384 | def test_read_buffer_small_chunks(self): |
|
399 | def test_read_buffer_small_chunks(self): | |
385 | cctx = zstd.ZstdCompressor() |
|
400 | cctx = zstd.ZstdCompressor() | |
386 |
source = b |
|
401 | source = b"".join([b"foo" * 60, b"bar" * 60, b"baz" * 60]) | |
387 | frame = cctx.compress(source) |
|
402 | frame = cctx.compress(source) | |
388 |
|
403 | |||
389 | dctx = zstd.ZstdDecompressor() |
|
404 | dctx = zstd.ZstdDecompressor() | |
@@ -398,11 +413,11 b' class TestDecompressor_stream_reader(uni' | |||||
398 | chunks.append(chunk) |
|
413 | chunks.append(chunk) | |
399 | self.assertEqual(reader.tell(), sum(map(len, chunks))) |
|
414 | self.assertEqual(reader.tell(), sum(map(len, chunks))) | |
400 |
|
415 | |||
401 |
self.assertEqual(b |
|
416 | self.assertEqual(b"".join(chunks), source) | |
402 |
|
417 | |||
403 | def test_read_stream(self): |
|
418 | def test_read_stream(self): | |
404 | cctx = zstd.ZstdCompressor() |
|
419 | cctx = zstd.ZstdCompressor() | |
405 |
source = b |
|
420 | source = b"".join([b"foo" * 60, b"bar" * 60, b"baz" * 60]) | |
406 | frame = cctx.compress(source) |
|
421 | frame = cctx.compress(source) | |
407 |
|
422 | |||
408 | dctx = zstd.ZstdDecompressor() |
|
423 | dctx = zstd.ZstdDecompressor() | |
@@ -412,7 +427,7 b' class TestDecompressor_stream_reader(uni' | |||||
412 | chunk = reader.read(8192) |
|
427 | chunk = reader.read(8192) | |
413 | self.assertEqual(chunk, source) |
|
428 | self.assertEqual(chunk, source) | |
414 | self.assertEqual(reader.tell(), len(source)) |
|
429 | self.assertEqual(reader.tell(), len(source)) | |
415 |
self.assertEqual(reader.read(1), b |
|
430 | self.assertEqual(reader.read(1), b"") | |
416 | self.assertEqual(reader.tell(), len(source)) |
|
431 | self.assertEqual(reader.tell(), len(source)) | |
417 | self.assertFalse(reader.closed) |
|
432 | self.assertFalse(reader.closed) | |
418 |
|
433 | |||
@@ -420,7 +435,7 b' class TestDecompressor_stream_reader(uni' | |||||
420 |
|
435 | |||
421 | def test_read_stream_small_chunks(self): |
|
436 | def test_read_stream_small_chunks(self): | |
422 | cctx = zstd.ZstdCompressor() |
|
437 | cctx = zstd.ZstdCompressor() | |
423 |
source = b |
|
438 | source = b"".join([b"foo" * 60, b"bar" * 60, b"baz" * 60]) | |
424 | frame = cctx.compress(source) |
|
439 | frame = cctx.compress(source) | |
425 |
|
440 | |||
426 | dctx = zstd.ZstdDecompressor() |
|
441 | dctx = zstd.ZstdDecompressor() | |
@@ -435,11 +450,11 b' class TestDecompressor_stream_reader(uni' | |||||
435 | chunks.append(chunk) |
|
450 | chunks.append(chunk) | |
436 | self.assertEqual(reader.tell(), sum(map(len, chunks))) |
|
451 | self.assertEqual(reader.tell(), sum(map(len, chunks))) | |
437 |
|
452 | |||
438 |
self.assertEqual(b |
|
453 | self.assertEqual(b"".join(chunks), source) | |
439 |
|
454 | |||
440 | def test_read_after_exit(self): |
|
455 | def test_read_after_exit(self): | |
441 | cctx = zstd.ZstdCompressor() |
|
456 | cctx = zstd.ZstdCompressor() | |
442 |
frame = cctx.compress(b |
|
457 | frame = cctx.compress(b"foo" * 60) | |
443 |
|
458 | |||
444 | dctx = zstd.ZstdDecompressor() |
|
459 | dctx = zstd.ZstdDecompressor() | |
445 |
|
460 | |||
@@ -449,45 +464,46 b' class TestDecompressor_stream_reader(uni' | |||||
449 |
|
464 | |||
450 | self.assertTrue(reader.closed) |
|
465 | self.assertTrue(reader.closed) | |
451 |
|
466 | |||
452 |
with self.assertRaisesRegex |
|
467 | with self.assertRaisesRegex(ValueError, "stream is closed"): | |
453 | reader.read(10) |
|
468 | reader.read(10) | |
454 |
|
469 | |||
455 | def test_illegal_seeks(self): |
|
470 | def test_illegal_seeks(self): | |
456 | cctx = zstd.ZstdCompressor() |
|
471 | cctx = zstd.ZstdCompressor() | |
457 |
frame = cctx.compress(b |
|
472 | frame = cctx.compress(b"foo" * 60) | |
458 |
|
473 | |||
459 | dctx = zstd.ZstdDecompressor() |
|
474 | dctx = zstd.ZstdDecompressor() | |
460 |
|
475 | |||
461 | with dctx.stream_reader(frame) as reader: |
|
476 | with dctx.stream_reader(frame) as reader: | |
462 |
with self.assertRaisesRegex |
|
477 | with self.assertRaisesRegex(ValueError, "cannot seek to negative position"): | |
463 | 'cannot seek to negative position'): |
|
|||
464 | reader.seek(-1, os.SEEK_SET) |
|
478 | reader.seek(-1, os.SEEK_SET) | |
465 |
|
479 | |||
466 | reader.read(1) |
|
480 | reader.read(1) | |
467 |
|
481 | |||
468 |
with self.assertRaisesRegex |
|
482 | with self.assertRaisesRegex( | |
469 |
ValueError, |
|
483 | ValueError, "cannot seek zstd decompression stream backwards" | |
|
484 | ): | |||
470 | reader.seek(0, os.SEEK_SET) |
|
485 | reader.seek(0, os.SEEK_SET) | |
471 |
|
486 | |||
472 |
with self.assertRaisesRegex |
|
487 | with self.assertRaisesRegex( | |
473 |
ValueError, |
|
488 | ValueError, "cannot seek zstd decompression stream backwards" | |
|
489 | ): | |||
474 | reader.seek(-1, os.SEEK_CUR) |
|
490 | reader.seek(-1, os.SEEK_CUR) | |
475 |
|
491 | |||
476 |
with self.assertRaisesRegex |
|
492 | with self.assertRaisesRegex( | |
477 | ValueError, |
|
493 | ValueError, "zstd decompression streams cannot be seeked with SEEK_END" | |
478 | 'zstd decompression streams cannot be seeked with SEEK_END'): |
|
494 | ): | |
479 | reader.seek(0, os.SEEK_END) |
|
495 | reader.seek(0, os.SEEK_END) | |
480 |
|
496 | |||
481 | reader.close() |
|
497 | reader.close() | |
482 |
|
498 | |||
483 |
with self.assertRaisesRegex |
|
499 | with self.assertRaisesRegex(ValueError, "stream is closed"): | |
484 | reader.seek(4, os.SEEK_SET) |
|
500 | reader.seek(4, os.SEEK_SET) | |
485 |
|
501 | |||
486 |
with self.assertRaisesRegex |
|
502 | with self.assertRaisesRegex(ValueError, "stream is closed"): | |
487 | reader.seek(0) |
|
503 | reader.seek(0) | |
488 |
|
504 | |||
489 | def test_seek(self): |
|
505 | def test_seek(self): | |
490 |
source = b |
|
506 | source = b"foobar" * 60 | |
491 | cctx = zstd.ZstdCompressor() |
|
507 | cctx = zstd.ZstdCompressor() | |
492 | frame = cctx.compress(source) |
|
508 | frame = cctx.compress(source) | |
493 |
|
509 | |||
@@ -495,32 +511,32 b' class TestDecompressor_stream_reader(uni' | |||||
495 |
|
511 | |||
496 | with dctx.stream_reader(frame) as reader: |
|
512 | with dctx.stream_reader(frame) as reader: | |
497 | reader.seek(3) |
|
513 | reader.seek(3) | |
498 |
self.assertEqual(reader.read(3), b |
|
514 | self.assertEqual(reader.read(3), b"bar") | |
499 |
|
515 | |||
500 | reader.seek(4, os.SEEK_CUR) |
|
516 | reader.seek(4, os.SEEK_CUR) | |
501 |
self.assertEqual(reader.read(2), b |
|
517 | self.assertEqual(reader.read(2), b"ar") | |
502 |
|
518 | |||
503 | def test_no_context_manager(self): |
|
519 | def test_no_context_manager(self): | |
504 |
source = b |
|
520 | source = b"foobar" * 60 | |
505 | cctx = zstd.ZstdCompressor() |
|
521 | cctx = zstd.ZstdCompressor() | |
506 | frame = cctx.compress(source) |
|
522 | frame = cctx.compress(source) | |
507 |
|
523 | |||
508 | dctx = zstd.ZstdDecompressor() |
|
524 | dctx = zstd.ZstdDecompressor() | |
509 | reader = dctx.stream_reader(frame) |
|
525 | reader = dctx.stream_reader(frame) | |
510 |
|
526 | |||
511 |
self.assertEqual(reader.read(6), b |
|
527 | self.assertEqual(reader.read(6), b"foobar") | |
512 |
self.assertEqual(reader.read(18), b |
|
528 | self.assertEqual(reader.read(18), b"foobar" * 3) | |
513 | self.assertFalse(reader.closed) |
|
529 | self.assertFalse(reader.closed) | |
514 |
|
530 | |||
515 | # Calling close prevents subsequent use. |
|
531 | # Calling close prevents subsequent use. | |
516 | reader.close() |
|
532 | reader.close() | |
517 | self.assertTrue(reader.closed) |
|
533 | self.assertTrue(reader.closed) | |
518 |
|
534 | |||
519 |
with self.assertRaisesRegex |
|
535 | with self.assertRaisesRegex(ValueError, "stream is closed"): | |
520 | reader.read(6) |
|
536 | reader.read(6) | |
521 |
|
537 | |||
522 | def test_read_after_error(self): |
|
538 | def test_read_after_error(self): | |
523 |
source = io.BytesIO(b |
|
539 | source = io.BytesIO(b"") | |
524 | dctx = zstd.ZstdDecompressor() |
|
540 | dctx = zstd.ZstdDecompressor() | |
525 |
|
541 | |||
526 | reader = dctx.stream_reader(source) |
|
542 | reader = dctx.stream_reader(source) | |
@@ -529,7 +545,7 b' class TestDecompressor_stream_reader(uni' | |||||
529 | reader.read(0) |
|
545 | reader.read(0) | |
530 |
|
546 | |||
531 | with reader: |
|
547 | with reader: | |
532 |
with self.assertRaisesRegex |
|
548 | with self.assertRaisesRegex(ValueError, "stream is closed"): | |
533 | reader.read(100) |
|
549 | reader.read(100) | |
534 |
|
550 | |||
535 | def test_partial_read(self): |
|
551 | def test_partial_read(self): | |
@@ -553,87 +569,87 b' class TestDecompressor_stream_reader(uni' | |||||
553 | cctx = zstd.ZstdCompressor() |
|
569 | cctx = zstd.ZstdCompressor() | |
554 | source = io.BytesIO() |
|
570 | source = io.BytesIO() | |
555 | writer = cctx.stream_writer(source) |
|
571 | writer = cctx.stream_writer(source) | |
556 |
writer.write(b |
|
572 | writer.write(b"foo") | |
557 | writer.flush(zstd.FLUSH_FRAME) |
|
573 | writer.flush(zstd.FLUSH_FRAME) | |
558 |
writer.write(b |
|
574 | writer.write(b"bar") | |
559 | writer.flush(zstd.FLUSH_FRAME) |
|
575 | writer.flush(zstd.FLUSH_FRAME) | |
560 |
|
576 | |||
561 | dctx = zstd.ZstdDecompressor() |
|
577 | dctx = zstd.ZstdDecompressor() | |
562 |
|
578 | |||
563 | reader = dctx.stream_reader(source.getvalue()) |
|
579 | reader = dctx.stream_reader(source.getvalue()) | |
564 |
self.assertEqual(reader.read(2), b |
|
580 | self.assertEqual(reader.read(2), b"fo") | |
565 |
self.assertEqual(reader.read(2), b |
|
581 | self.assertEqual(reader.read(2), b"o") | |
566 |
self.assertEqual(reader.read(2), b |
|
582 | self.assertEqual(reader.read(2), b"ba") | |
567 |
self.assertEqual(reader.read(2), b |
|
583 | self.assertEqual(reader.read(2), b"r") | |
568 |
|
584 | |||
569 | source.seek(0) |
|
585 | source.seek(0) | |
570 | reader = dctx.stream_reader(source) |
|
586 | reader = dctx.stream_reader(source) | |
571 |
self.assertEqual(reader.read(2), b |
|
587 | self.assertEqual(reader.read(2), b"fo") | |
572 |
self.assertEqual(reader.read(2), b |
|
588 | self.assertEqual(reader.read(2), b"o") | |
573 |
self.assertEqual(reader.read(2), b |
|
589 | self.assertEqual(reader.read(2), b"ba") | |
574 |
self.assertEqual(reader.read(2), b |
|
590 | self.assertEqual(reader.read(2), b"r") | |
575 |
|
591 | |||
576 | reader = dctx.stream_reader(source.getvalue()) |
|
592 | reader = dctx.stream_reader(source.getvalue()) | |
577 |
self.assertEqual(reader.read(3), b |
|
593 | self.assertEqual(reader.read(3), b"foo") | |
578 |
self.assertEqual(reader.read(3), b |
|
594 | self.assertEqual(reader.read(3), b"bar") | |
579 |
|
595 | |||
580 | source.seek(0) |
|
596 | source.seek(0) | |
581 | reader = dctx.stream_reader(source) |
|
597 | reader = dctx.stream_reader(source) | |
582 |
self.assertEqual(reader.read(3), b |
|
598 | self.assertEqual(reader.read(3), b"foo") | |
583 |
self.assertEqual(reader.read(3), b |
|
599 | self.assertEqual(reader.read(3), b"bar") | |
584 |
|
600 | |||
585 | reader = dctx.stream_reader(source.getvalue()) |
|
601 | reader = dctx.stream_reader(source.getvalue()) | |
586 |
self.assertEqual(reader.read(4), b |
|
602 | self.assertEqual(reader.read(4), b"foo") | |
587 |
self.assertEqual(reader.read(4), b |
|
603 | self.assertEqual(reader.read(4), b"bar") | |
588 |
|
604 | |||
589 | source.seek(0) |
|
605 | source.seek(0) | |
590 | reader = dctx.stream_reader(source) |
|
606 | reader = dctx.stream_reader(source) | |
591 |
self.assertEqual(reader.read(4), b |
|
607 | self.assertEqual(reader.read(4), b"foo") | |
592 |
self.assertEqual(reader.read(4), b |
|
608 | self.assertEqual(reader.read(4), b"bar") | |
593 |
|
609 | |||
594 | reader = dctx.stream_reader(source.getvalue()) |
|
610 | reader = dctx.stream_reader(source.getvalue()) | |
595 |
self.assertEqual(reader.read(128), b |
|
611 | self.assertEqual(reader.read(128), b"foo") | |
596 |
self.assertEqual(reader.read(128), b |
|
612 | self.assertEqual(reader.read(128), b"bar") | |
597 |
|
613 | |||
598 | source.seek(0) |
|
614 | source.seek(0) | |
599 | reader = dctx.stream_reader(source) |
|
615 | reader = dctx.stream_reader(source) | |
600 |
self.assertEqual(reader.read(128), b |
|
616 | self.assertEqual(reader.read(128), b"foo") | |
601 |
self.assertEqual(reader.read(128), b |
|
617 | self.assertEqual(reader.read(128), b"bar") | |
602 |
|
618 | |||
603 | # Now tests for reads spanning frames. |
|
619 | # Now tests for reads spanning frames. | |
604 | reader = dctx.stream_reader(source.getvalue(), read_across_frames=True) |
|
620 | reader = dctx.stream_reader(source.getvalue(), read_across_frames=True) | |
605 |
self.assertEqual(reader.read(3), b |
|
621 | self.assertEqual(reader.read(3), b"foo") | |
606 |
self.assertEqual(reader.read(3), b |
|
622 | self.assertEqual(reader.read(3), b"bar") | |
607 |
|
623 | |||
608 | source.seek(0) |
|
624 | source.seek(0) | |
609 | reader = dctx.stream_reader(source, read_across_frames=True) |
|
625 | reader = dctx.stream_reader(source, read_across_frames=True) | |
610 |
self.assertEqual(reader.read(3), b |
|
626 | self.assertEqual(reader.read(3), b"foo") | |
611 |
self.assertEqual(reader.read(3), b |
|
627 | self.assertEqual(reader.read(3), b"bar") | |
612 |
|
628 | |||
613 | reader = dctx.stream_reader(source.getvalue(), read_across_frames=True) |
|
629 | reader = dctx.stream_reader(source.getvalue(), read_across_frames=True) | |
614 |
self.assertEqual(reader.read(6), b |
|
630 | self.assertEqual(reader.read(6), b"foobar") | |
615 |
|
631 | |||
616 | source.seek(0) |
|
632 | source.seek(0) | |
617 | reader = dctx.stream_reader(source, read_across_frames=True) |
|
633 | reader = dctx.stream_reader(source, read_across_frames=True) | |
618 |
self.assertEqual(reader.read(6), b |
|
634 | self.assertEqual(reader.read(6), b"foobar") | |
619 |
|
635 | |||
620 | reader = dctx.stream_reader(source.getvalue(), read_across_frames=True) |
|
636 | reader = dctx.stream_reader(source.getvalue(), read_across_frames=True) | |
621 |
self.assertEqual(reader.read(7), b |
|
637 | self.assertEqual(reader.read(7), b"foobar") | |
622 |
|
638 | |||
623 | source.seek(0) |
|
639 | source.seek(0) | |
624 | reader = dctx.stream_reader(source, read_across_frames=True) |
|
640 | reader = dctx.stream_reader(source, read_across_frames=True) | |
625 |
self.assertEqual(reader.read(7), b |
|
641 | self.assertEqual(reader.read(7), b"foobar") | |
626 |
|
642 | |||
627 | reader = dctx.stream_reader(source.getvalue(), read_across_frames=True) |
|
643 | reader = dctx.stream_reader(source.getvalue(), read_across_frames=True) | |
628 |
self.assertEqual(reader.read(128), b |
|
644 | self.assertEqual(reader.read(128), b"foobar") | |
629 |
|
645 | |||
630 | source.seek(0) |
|
646 | source.seek(0) | |
631 | reader = dctx.stream_reader(source, read_across_frames=True) |
|
647 | reader = dctx.stream_reader(source, read_across_frames=True) | |
632 |
self.assertEqual(reader.read(128), b |
|
648 | self.assertEqual(reader.read(128), b"foobar") | |
633 |
|
649 | |||
634 | def test_readinto(self): |
|
650 | def test_readinto(self): | |
635 | cctx = zstd.ZstdCompressor() |
|
651 | cctx = zstd.ZstdCompressor() | |
636 |
foo = cctx.compress(b |
|
652 | foo = cctx.compress(b"foo") | |
637 |
|
653 | |||
638 | dctx = zstd.ZstdDecompressor() |
|
654 | dctx = zstd.ZstdDecompressor() | |
639 |
|
655 | |||
@@ -641,116 +657,116 b' class TestDecompressor_stream_reader(uni' | |||||
641 | # The exact exception varies based on the backend. |
|
657 | # The exact exception varies based on the backend. | |
642 | reader = dctx.stream_reader(foo) |
|
658 | reader = dctx.stream_reader(foo) | |
643 | with self.assertRaises(Exception): |
|
659 | with self.assertRaises(Exception): | |
644 |
reader.readinto(b |
|
660 | reader.readinto(b"foobar") | |
645 |
|
661 | |||
646 | # readinto() with sufficiently large destination. |
|
662 | # readinto() with sufficiently large destination. | |
647 | b = bytearray(1024) |
|
663 | b = bytearray(1024) | |
648 | reader = dctx.stream_reader(foo) |
|
664 | reader = dctx.stream_reader(foo) | |
649 | self.assertEqual(reader.readinto(b), 3) |
|
665 | self.assertEqual(reader.readinto(b), 3) | |
650 |
self.assertEqual(b[0:3], b |
|
666 | self.assertEqual(b[0:3], b"foo") | |
651 | self.assertEqual(reader.readinto(b), 0) |
|
667 | self.assertEqual(reader.readinto(b), 0) | |
652 |
self.assertEqual(b[0:3], b |
|
668 | self.assertEqual(b[0:3], b"foo") | |
653 |
|
669 | |||
654 | # readinto() with small reads. |
|
670 | # readinto() with small reads. | |
655 | b = bytearray(1024) |
|
671 | b = bytearray(1024) | |
656 | reader = dctx.stream_reader(foo, read_size=1) |
|
672 | reader = dctx.stream_reader(foo, read_size=1) | |
657 | self.assertEqual(reader.readinto(b), 3) |
|
673 | self.assertEqual(reader.readinto(b), 3) | |
658 |
self.assertEqual(b[0:3], b |
|
674 | self.assertEqual(b[0:3], b"foo") | |
659 |
|
675 | |||
660 | # Too small destination buffer. |
|
676 | # Too small destination buffer. | |
661 | b = bytearray(2) |
|
677 | b = bytearray(2) | |
662 | reader = dctx.stream_reader(foo) |
|
678 | reader = dctx.stream_reader(foo) | |
663 | self.assertEqual(reader.readinto(b), 2) |
|
679 | self.assertEqual(reader.readinto(b), 2) | |
664 |
self.assertEqual(b[:], b |
|
680 | self.assertEqual(b[:], b"fo") | |
665 |
|
681 | |||
666 | def test_readinto1(self): |
|
682 | def test_readinto1(self): | |
667 | cctx = zstd.ZstdCompressor() |
|
683 | cctx = zstd.ZstdCompressor() | |
668 |
foo = cctx.compress(b |
|
684 | foo = cctx.compress(b"foo") | |
669 |
|
685 | |||
670 | dctx = zstd.ZstdDecompressor() |
|
686 | dctx = zstd.ZstdDecompressor() | |
671 |
|
687 | |||
672 | reader = dctx.stream_reader(foo) |
|
688 | reader = dctx.stream_reader(foo) | |
673 | with self.assertRaises(Exception): |
|
689 | with self.assertRaises(Exception): | |
674 |
reader.readinto1(b |
|
690 | reader.readinto1(b"foobar") | |
675 |
|
691 | |||
676 | # Sufficiently large destination. |
|
692 | # Sufficiently large destination. | |
677 | b = bytearray(1024) |
|
693 | b = bytearray(1024) | |
678 | reader = dctx.stream_reader(foo) |
|
694 | reader = dctx.stream_reader(foo) | |
679 | self.assertEqual(reader.readinto1(b), 3) |
|
695 | self.assertEqual(reader.readinto1(b), 3) | |
680 |
self.assertEqual(b[0:3], b |
|
696 | self.assertEqual(b[0:3], b"foo") | |
681 | self.assertEqual(reader.readinto1(b), 0) |
|
697 | self.assertEqual(reader.readinto1(b), 0) | |
682 |
self.assertEqual(b[0:3], b |
|
698 | self.assertEqual(b[0:3], b"foo") | |
683 |
|
699 | |||
684 | # readinto() with small reads. |
|
700 | # readinto() with small reads. | |
685 | b = bytearray(1024) |
|
701 | b = bytearray(1024) | |
686 | reader = dctx.stream_reader(foo, read_size=1) |
|
702 | reader = dctx.stream_reader(foo, read_size=1) | |
687 | self.assertEqual(reader.readinto1(b), 3) |
|
703 | self.assertEqual(reader.readinto1(b), 3) | |
688 |
self.assertEqual(b[0:3], b |
|
704 | self.assertEqual(b[0:3], b"foo") | |
689 |
|
705 | |||
690 | # Too small destination buffer. |
|
706 | # Too small destination buffer. | |
691 | b = bytearray(2) |
|
707 | b = bytearray(2) | |
692 | reader = dctx.stream_reader(foo) |
|
708 | reader = dctx.stream_reader(foo) | |
693 | self.assertEqual(reader.readinto1(b), 2) |
|
709 | self.assertEqual(reader.readinto1(b), 2) | |
694 |
self.assertEqual(b[:], b |
|
710 | self.assertEqual(b[:], b"fo") | |
695 |
|
711 | |||
696 | def test_readall(self): |
|
712 | def test_readall(self): | |
697 | cctx = zstd.ZstdCompressor() |
|
713 | cctx = zstd.ZstdCompressor() | |
698 |
foo = cctx.compress(b |
|
714 | foo = cctx.compress(b"foo") | |
699 |
|
715 | |||
700 | dctx = zstd.ZstdDecompressor() |
|
716 | dctx = zstd.ZstdDecompressor() | |
701 | reader = dctx.stream_reader(foo) |
|
717 | reader = dctx.stream_reader(foo) | |
702 |
|
718 | |||
703 |
self.assertEqual(reader.readall(), b |
|
719 | self.assertEqual(reader.readall(), b"foo") | |
704 |
|
720 | |||
705 | def test_read1(self): |
|
721 | def test_read1(self): | |
706 | cctx = zstd.ZstdCompressor() |
|
722 | cctx = zstd.ZstdCompressor() | |
707 |
foo = cctx.compress(b |
|
723 | foo = cctx.compress(b"foo") | |
708 |
|
724 | |||
709 | dctx = zstd.ZstdDecompressor() |
|
725 | dctx = zstd.ZstdDecompressor() | |
710 |
|
726 | |||
711 | b = OpCountingBytesIO(foo) |
|
727 | b = OpCountingBytesIO(foo) | |
712 | reader = dctx.stream_reader(b) |
|
728 | reader = dctx.stream_reader(b) | |
713 |
|
729 | |||
714 |
self.assertEqual(reader.read1(), b |
|
730 | self.assertEqual(reader.read1(), b"foo") | |
715 | self.assertEqual(b._read_count, 1) |
|
731 | self.assertEqual(b._read_count, 1) | |
716 |
|
732 | |||
717 | b = OpCountingBytesIO(foo) |
|
733 | b = OpCountingBytesIO(foo) | |
718 | reader = dctx.stream_reader(b) |
|
734 | reader = dctx.stream_reader(b) | |
719 |
|
735 | |||
720 |
self.assertEqual(reader.read1(0), b |
|
736 | self.assertEqual(reader.read1(0), b"") | |
721 |
self.assertEqual(reader.read1(2), b |
|
737 | self.assertEqual(reader.read1(2), b"fo") | |
722 | self.assertEqual(b._read_count, 1) |
|
738 | self.assertEqual(b._read_count, 1) | |
723 |
self.assertEqual(reader.read1(1), b |
|
739 | self.assertEqual(reader.read1(1), b"o") | |
724 | self.assertEqual(b._read_count, 1) |
|
740 | self.assertEqual(b._read_count, 1) | |
725 |
self.assertEqual(reader.read1(1), b |
|
741 | self.assertEqual(reader.read1(1), b"") | |
726 | self.assertEqual(b._read_count, 2) |
|
742 | self.assertEqual(b._read_count, 2) | |
727 |
|
743 | |||
728 | def test_read_lines(self): |
|
744 | def test_read_lines(self): | |
729 | cctx = zstd.ZstdCompressor() |
|
745 | cctx = zstd.ZstdCompressor() | |
730 |
source = b |
|
746 | source = b"\n".join(("line %d" % i).encode("ascii") for i in range(1024)) | |
731 |
|
747 | |||
732 | frame = cctx.compress(source) |
|
748 | frame = cctx.compress(source) | |
733 |
|
749 | |||
734 | dctx = zstd.ZstdDecompressor() |
|
750 | dctx = zstd.ZstdDecompressor() | |
735 | reader = dctx.stream_reader(frame) |
|
751 | reader = dctx.stream_reader(frame) | |
736 |
tr = io.TextIOWrapper(reader, encoding= |
|
752 | tr = io.TextIOWrapper(reader, encoding="utf-8") | |
737 |
|
753 | |||
738 | lines = [] |
|
754 | lines = [] | |
739 | for line in tr: |
|
755 | for line in tr: | |
740 |
lines.append(line.encode( |
|
756 | lines.append(line.encode("utf-8")) | |
741 |
|
757 | |||
742 | self.assertEqual(len(lines), 1024) |
|
758 | self.assertEqual(len(lines), 1024) | |
743 |
self.assertEqual(b |
|
759 | self.assertEqual(b"".join(lines), source) | |
744 |
|
760 | |||
745 | reader = dctx.stream_reader(frame) |
|
761 | reader = dctx.stream_reader(frame) | |
746 |
tr = io.TextIOWrapper(reader, encoding= |
|
762 | tr = io.TextIOWrapper(reader, encoding="utf-8") | |
747 |
|
763 | |||
748 | lines = tr.readlines() |
|
764 | lines = tr.readlines() | |
749 | self.assertEqual(len(lines), 1024) |
|
765 | self.assertEqual(len(lines), 1024) | |
750 |
self.assertEqual( |
|
766 | self.assertEqual("".join(lines).encode("utf-8"), source) | |
751 |
|
767 | |||
752 | reader = dctx.stream_reader(frame) |
|
768 | reader = dctx.stream_reader(frame) | |
753 |
tr = io.TextIOWrapper(reader, encoding= |
|
769 | tr = io.TextIOWrapper(reader, encoding="utf-8") | |
754 |
|
770 | |||
755 | lines = [] |
|
771 | lines = [] | |
756 | while True: |
|
772 | while True: | |
@@ -758,26 +774,26 b' class TestDecompressor_stream_reader(uni' | |||||
758 | if not line: |
|
774 | if not line: | |
759 | break |
|
775 | break | |
760 |
|
776 | |||
761 |
lines.append(line.encode( |
|
777 | lines.append(line.encode("utf-8")) | |
762 |
|
778 | |||
763 | self.assertEqual(len(lines), 1024) |
|
779 | self.assertEqual(len(lines), 1024) | |
764 |
self.assertEqual(b |
|
780 | self.assertEqual(b"".join(lines), source) | |
765 |
|
781 | |||
766 |
|
782 | |||
767 | @make_cffi |
|
783 | @make_cffi | |
768 |
class TestDecompressor_decompressobj( |
|
784 | class TestDecompressor_decompressobj(TestCase): | |
769 | def test_simple(self): |
|
785 | def test_simple(self): | |
770 |
data = zstd.ZstdCompressor(level=1).compress(b |
|
786 | data = zstd.ZstdCompressor(level=1).compress(b"foobar") | |
771 |
|
787 | |||
772 | dctx = zstd.ZstdDecompressor() |
|
788 | dctx = zstd.ZstdDecompressor() | |
773 | dobj = dctx.decompressobj() |
|
789 | dobj = dctx.decompressobj() | |
774 |
self.assertEqual(dobj.decompress(data), b |
|
790 | self.assertEqual(dobj.decompress(data), b"foobar") | |
775 | self.assertIsNone(dobj.flush()) |
|
791 | self.assertIsNone(dobj.flush()) | |
776 | self.assertIsNone(dobj.flush(10)) |
|
792 | self.assertIsNone(dobj.flush(10)) | |
777 | self.assertIsNone(dobj.flush(length=100)) |
|
793 | self.assertIsNone(dobj.flush(length=100)) | |
778 |
|
794 | |||
779 | def test_input_types(self): |
|
795 | def test_input_types(self): | |
780 |
compressed = zstd.ZstdCompressor(level=1).compress(b |
|
796 | compressed = zstd.ZstdCompressor(level=1).compress(b"foo") | |
781 |
|
797 | |||
782 | dctx = zstd.ZstdDecompressor() |
|
798 | dctx = zstd.ZstdDecompressor() | |
783 |
|
799 | |||
@@ -795,28 +811,28 b' class TestDecompressor_decompressobj(uni' | |||||
795 | self.assertIsNone(dobj.flush()) |
|
811 | self.assertIsNone(dobj.flush()) | |
796 | self.assertIsNone(dobj.flush(10)) |
|
812 | self.assertIsNone(dobj.flush(10)) | |
797 | self.assertIsNone(dobj.flush(length=100)) |
|
813 | self.assertIsNone(dobj.flush(length=100)) | |
798 |
self.assertEqual(dobj.decompress(source), b |
|
814 | self.assertEqual(dobj.decompress(source), b"foo") | |
799 | self.assertIsNone(dobj.flush()) |
|
815 | self.assertIsNone(dobj.flush()) | |
800 |
|
816 | |||
801 | def test_reuse(self): |
|
817 | def test_reuse(self): | |
802 |
data = zstd.ZstdCompressor(level=1).compress(b |
|
818 | data = zstd.ZstdCompressor(level=1).compress(b"foobar") | |
803 |
|
819 | |||
804 | dctx = zstd.ZstdDecompressor() |
|
820 | dctx = zstd.ZstdDecompressor() | |
805 | dobj = dctx.decompressobj() |
|
821 | dobj = dctx.decompressobj() | |
806 | dobj.decompress(data) |
|
822 | dobj.decompress(data) | |
807 |
|
823 | |||
808 |
with self.assertRaisesRegex |
|
824 | with self.assertRaisesRegex(zstd.ZstdError, "cannot use a decompressobj"): | |
809 | dobj.decompress(data) |
|
825 | dobj.decompress(data) | |
810 | self.assertIsNone(dobj.flush()) |
|
826 | self.assertIsNone(dobj.flush()) | |
811 |
|
827 | |||
812 | def test_bad_write_size(self): |
|
828 | def test_bad_write_size(self): | |
813 | dctx = zstd.ZstdDecompressor() |
|
829 | dctx = zstd.ZstdDecompressor() | |
814 |
|
830 | |||
815 |
with self.assertRaisesRegex |
|
831 | with self.assertRaisesRegex(ValueError, "write_size must be positive"): | |
816 | dctx.decompressobj(write_size=0) |
|
832 | dctx.decompressobj(write_size=0) | |
817 |
|
833 | |||
818 | def test_write_size(self): |
|
834 | def test_write_size(self): | |
819 |
source = b |
|
835 | source = b"foo" * 64 + b"bar" * 128 | |
820 | data = zstd.ZstdCompressor(level=1).compress(source) |
|
836 | data = zstd.ZstdCompressor(level=1).compress(source) | |
821 |
|
837 | |||
822 | dctx = zstd.ZstdDecompressor() |
|
838 | dctx = zstd.ZstdDecompressor() | |
@@ -836,7 +852,7 b' def decompress_via_writer(data):' | |||||
836 |
|
852 | |||
837 |
|
853 | |||
838 | @make_cffi |
|
854 | @make_cffi | |
839 |
class TestDecompressor_stream_writer( |
|
855 | class TestDecompressor_stream_writer(TestCase): | |
840 | def test_io_api(self): |
|
856 | def test_io_api(self): | |
841 | buffer = io.BytesIO() |
|
857 | buffer = io.BytesIO() | |
842 | dctx = zstd.ZstdDecompressor() |
|
858 | dctx = zstd.ZstdDecompressor() | |
@@ -908,14 +924,14 b' class TestDecompressor_stream_writer(uni' | |||||
908 | writer.fileno() |
|
924 | writer.fileno() | |
909 |
|
925 | |||
910 | def test_fileno_file(self): |
|
926 | def test_fileno_file(self): | |
911 |
with tempfile.TemporaryFile( |
|
927 | with tempfile.TemporaryFile("wb") as tf: | |
912 | dctx = zstd.ZstdDecompressor() |
|
928 | dctx = zstd.ZstdDecompressor() | |
913 | writer = dctx.stream_writer(tf) |
|
929 | writer = dctx.stream_writer(tf) | |
914 |
|
930 | |||
915 | self.assertEqual(writer.fileno(), tf.fileno()) |
|
931 | self.assertEqual(writer.fileno(), tf.fileno()) | |
916 |
|
932 | |||
917 | def test_close(self): |
|
933 | def test_close(self): | |
918 |
foo = zstd.ZstdCompressor().compress(b |
|
934 | foo = zstd.ZstdCompressor().compress(b"foo") | |
919 |
|
935 | |||
920 | buffer = NonClosingBytesIO() |
|
936 | buffer = NonClosingBytesIO() | |
921 | dctx = zstd.ZstdDecompressor() |
|
937 | dctx = zstd.ZstdDecompressor() | |
@@ -928,17 +944,17 b' class TestDecompressor_stream_writer(uni' | |||||
928 | self.assertTrue(writer.closed) |
|
944 | self.assertTrue(writer.closed) | |
929 | self.assertTrue(buffer.closed) |
|
945 | self.assertTrue(buffer.closed) | |
930 |
|
946 | |||
931 |
with self.assertRaisesRegex |
|
947 | with self.assertRaisesRegex(ValueError, "stream is closed"): | |
932 |
writer.write(b |
|
948 | writer.write(b"") | |
933 |
|
949 | |||
934 |
with self.assertRaisesRegex |
|
950 | with self.assertRaisesRegex(ValueError, "stream is closed"): | |
935 | writer.flush() |
|
951 | writer.flush() | |
936 |
|
952 | |||
937 |
with self.assertRaisesRegex |
|
953 | with self.assertRaisesRegex(ValueError, "stream is closed"): | |
938 | with writer: |
|
954 | with writer: | |
939 | pass |
|
955 | pass | |
940 |
|
956 | |||
941 |
self.assertEqual(buffer.getvalue(), b |
|
957 | self.assertEqual(buffer.getvalue(), b"foo") | |
942 |
|
958 | |||
943 | # Context manager exit should close stream. |
|
959 | # Context manager exit should close stream. | |
944 | buffer = NonClosingBytesIO() |
|
960 | buffer = NonClosingBytesIO() | |
@@ -948,7 +964,7 b' class TestDecompressor_stream_writer(uni' | |||||
948 | writer.write(foo) |
|
964 | writer.write(foo) | |
949 |
|
965 | |||
950 | self.assertTrue(writer.closed) |
|
966 | self.assertTrue(writer.closed) | |
951 |
self.assertEqual(buffer.getvalue(), b |
|
967 | self.assertEqual(buffer.getvalue(), b"foo") | |
952 |
|
968 | |||
953 | def test_flush(self): |
|
969 | def test_flush(self): | |
954 | buffer = OpCountingBytesIO() |
|
970 | buffer = OpCountingBytesIO() | |
@@ -962,12 +978,12 b' class TestDecompressor_stream_writer(uni' | |||||
962 |
|
978 | |||
963 | def test_empty_roundtrip(self): |
|
979 | def test_empty_roundtrip(self): | |
964 | cctx = zstd.ZstdCompressor() |
|
980 | cctx = zstd.ZstdCompressor() | |
965 |
empty = cctx.compress(b |
|
981 | empty = cctx.compress(b"") | |
966 |
self.assertEqual(decompress_via_writer(empty), b |
|
982 | self.assertEqual(decompress_via_writer(empty), b"") | |
967 |
|
983 | |||
968 | def test_input_types(self): |
|
984 | def test_input_types(self): | |
969 | cctx = zstd.ZstdCompressor(level=1) |
|
985 | cctx = zstd.ZstdCompressor(level=1) | |
970 |
compressed = cctx.compress(b |
|
986 | compressed = cctx.compress(b"foo") | |
971 |
|
987 | |||
972 | mutable_array = bytearray(len(compressed)) |
|
988 | mutable_array = bytearray(len(compressed)) | |
973 | mutable_array[:] = compressed |
|
989 | mutable_array[:] = compressed | |
@@ -984,25 +1000,25 b' class TestDecompressor_stream_writer(uni' | |||||
984 |
|
1000 | |||
985 | decompressor = dctx.stream_writer(buffer) |
|
1001 | decompressor = dctx.stream_writer(buffer) | |
986 | decompressor.write(source) |
|
1002 | decompressor.write(source) | |
987 |
self.assertEqual(buffer.getvalue(), b |
|
1003 | self.assertEqual(buffer.getvalue(), b"foo") | |
988 |
|
1004 | |||
989 | buffer = NonClosingBytesIO() |
|
1005 | buffer = NonClosingBytesIO() | |
990 |
|
1006 | |||
991 | with dctx.stream_writer(buffer) as decompressor: |
|
1007 | with dctx.stream_writer(buffer) as decompressor: | |
992 | self.assertEqual(decompressor.write(source), 3) |
|
1008 | self.assertEqual(decompressor.write(source), 3) | |
993 |
|
1009 | |||
994 |
self.assertEqual(buffer.getvalue(), b |
|
1010 | self.assertEqual(buffer.getvalue(), b"foo") | |
995 |
|
1011 | |||
996 | buffer = io.BytesIO() |
|
1012 | buffer = io.BytesIO() | |
997 | writer = dctx.stream_writer(buffer, write_return_read=True) |
|
1013 | writer = dctx.stream_writer(buffer, write_return_read=True) | |
998 | self.assertEqual(writer.write(source), len(source)) |
|
1014 | self.assertEqual(writer.write(source), len(source)) | |
999 |
self.assertEqual(buffer.getvalue(), b |
|
1015 | self.assertEqual(buffer.getvalue(), b"foo") | |
1000 |
|
1016 | |||
1001 | def test_large_roundtrip(self): |
|
1017 | def test_large_roundtrip(self): | |
1002 | chunks = [] |
|
1018 | chunks = [] | |
1003 | for i in range(255): |
|
1019 | for i in range(255): | |
1004 |
chunks.append(struct.Struct( |
|
1020 | chunks.append(struct.Struct(">B").pack(i) * 16384) | |
1005 |
orig = b |
|
1021 | orig = b"".join(chunks) | |
1006 | cctx = zstd.ZstdCompressor() |
|
1022 | cctx = zstd.ZstdCompressor() | |
1007 | compressed = cctx.compress(orig) |
|
1023 | compressed = cctx.compress(orig) | |
1008 |
|
1024 | |||
@@ -1012,9 +1028,9 b' class TestDecompressor_stream_writer(uni' | |||||
1012 | chunks = [] |
|
1028 | chunks = [] | |
1013 | for i in range(255): |
|
1029 | for i in range(255): | |
1014 | for j in range(255): |
|
1030 | for j in range(255): | |
1015 |
chunks.append(struct.Struct( |
|
1031 | chunks.append(struct.Struct(">B").pack(j) * i) | |
1016 |
|
1032 | |||
1017 |
orig = b |
|
1033 | orig = b"".join(chunks) | |
1018 | cctx = zstd.ZstdCompressor() |
|
1034 | cctx = zstd.ZstdCompressor() | |
1019 | compressed = cctx.compress(orig) |
|
1035 | compressed = cctx.compress(orig) | |
1020 |
|
1036 | |||
@@ -1042,13 +1058,13 b' class TestDecompressor_stream_writer(uni' | |||||
1042 | def test_dictionary(self): |
|
1058 | def test_dictionary(self): | |
1043 | samples = [] |
|
1059 | samples = [] | |
1044 | for i in range(128): |
|
1060 | for i in range(128): | |
1045 |
samples.append(b |
|
1061 | samples.append(b"foo" * 64) | |
1046 |
samples.append(b |
|
1062 | samples.append(b"bar" * 64) | |
1047 |
samples.append(b |
|
1063 | samples.append(b"foobar" * 64) | |
1048 |
|
1064 | |||
1049 | d = zstd.train_dictionary(8192, samples) |
|
1065 | d = zstd.train_dictionary(8192, samples) | |
1050 |
|
1066 | |||
1051 |
orig = b |
|
1067 | orig = b"foobar" * 16384 | |
1052 | buffer = NonClosingBytesIO() |
|
1068 | buffer = NonClosingBytesIO() | |
1053 | cctx = zstd.ZstdCompressor(dict_data=d) |
|
1069 | cctx = zstd.ZstdCompressor(dict_data=d) | |
1054 | with cctx.stream_writer(buffer) as compressor: |
|
1070 | with cctx.stream_writer(buffer) as compressor: | |
@@ -1083,22 +1099,22 b' class TestDecompressor_stream_writer(uni' | |||||
1083 | self.assertGreater(size, 100000) |
|
1099 | self.assertGreater(size, 100000) | |
1084 |
|
1100 | |||
1085 | def test_write_size(self): |
|
1101 | def test_write_size(self): | |
1086 |
source = zstd.ZstdCompressor().compress(b |
|
1102 | source = zstd.ZstdCompressor().compress(b"foobarfoobar") | |
1087 | dest = OpCountingBytesIO() |
|
1103 | dest = OpCountingBytesIO() | |
1088 | dctx = zstd.ZstdDecompressor() |
|
1104 | dctx = zstd.ZstdDecompressor() | |
1089 | with dctx.stream_writer(dest, write_size=1) as decompressor: |
|
1105 | with dctx.stream_writer(dest, write_size=1) as decompressor: | |
1090 |
s = struct.Struct( |
|
1106 | s = struct.Struct(">B") | |
1091 | for c in source: |
|
1107 | for c in source: | |
1092 | if not isinstance(c, str): |
|
1108 | if not isinstance(c, str): | |
1093 | c = s.pack(c) |
|
1109 | c = s.pack(c) | |
1094 | decompressor.write(c) |
|
1110 | decompressor.write(c) | |
1095 |
|
1111 | |||
1096 |
self.assertEqual(dest.getvalue(), b |
|
1112 | self.assertEqual(dest.getvalue(), b"foobarfoobar") | |
1097 | self.assertEqual(dest._write_count, len(dest.getvalue())) |
|
1113 | self.assertEqual(dest._write_count, len(dest.getvalue())) | |
1098 |
|
1114 | |||
1099 |
|
1115 | |||
1100 | @make_cffi |
|
1116 | @make_cffi | |
1101 |
class TestDecompressor_read_to_iter( |
|
1117 | class TestDecompressor_read_to_iter(TestCase): | |
1102 | def test_type_validation(self): |
|
1118 | def test_type_validation(self): | |
1103 | dctx = zstd.ZstdDecompressor() |
|
1119 | dctx = zstd.ZstdDecompressor() | |
1104 |
|
1120 | |||
@@ -1106,10 +1122,10 b' class TestDecompressor_read_to_iter(unit' | |||||
1106 | dctx.read_to_iter(io.BytesIO()) |
|
1122 | dctx.read_to_iter(io.BytesIO()) | |
1107 |
|
1123 | |||
1108 | # Buffer protocol works. |
|
1124 | # Buffer protocol works. | |
1109 |
dctx.read_to_iter(b |
|
1125 | dctx.read_to_iter(b"foobar") | |
1110 |
|
1126 | |||
1111 |
with self.assertRaisesRegex |
|
1127 | with self.assertRaisesRegex(ValueError, "must pass an object with a read"): | |
1112 |
b |
|
1128 | b"".join(dctx.read_to_iter(True)) | |
1113 |
|
1129 | |||
1114 | def test_empty_input(self): |
|
1130 | def test_empty_input(self): | |
1115 | dctx = zstd.ZstdDecompressor() |
|
1131 | dctx = zstd.ZstdDecompressor() | |
@@ -1120,25 +1136,25 b' class TestDecompressor_read_to_iter(unit' | |||||
1120 | with self.assertRaises(StopIteration): |
|
1136 | with self.assertRaises(StopIteration): | |
1121 | next(it) |
|
1137 | next(it) | |
1122 |
|
1138 | |||
1123 |
it = dctx.read_to_iter(b |
|
1139 | it = dctx.read_to_iter(b"") | |
1124 | with self.assertRaises(StopIteration): |
|
1140 | with self.assertRaises(StopIteration): | |
1125 | next(it) |
|
1141 | next(it) | |
1126 |
|
1142 | |||
1127 | def test_invalid_input(self): |
|
1143 | def test_invalid_input(self): | |
1128 | dctx = zstd.ZstdDecompressor() |
|
1144 | dctx = zstd.ZstdDecompressor() | |
1129 |
|
1145 | |||
1130 |
source = io.BytesIO(b |
|
1146 | source = io.BytesIO(b"foobar") | |
1131 | it = dctx.read_to_iter(source) |
|
1147 | it = dctx.read_to_iter(source) | |
1132 |
with self.assertRaisesRegex |
|
1148 | with self.assertRaisesRegex(zstd.ZstdError, "Unknown frame descriptor"): | |
1133 | next(it) |
|
1149 | next(it) | |
1134 |
|
1150 | |||
1135 |
it = dctx.read_to_iter(b |
|
1151 | it = dctx.read_to_iter(b"foobar") | |
1136 |
with self.assertRaisesRegex |
|
1152 | with self.assertRaisesRegex(zstd.ZstdError, "Unknown frame descriptor"): | |
1137 | next(it) |
|
1153 | next(it) | |
1138 |
|
1154 | |||
1139 | def test_empty_roundtrip(self): |
|
1155 | def test_empty_roundtrip(self): | |
1140 | cctx = zstd.ZstdCompressor(level=1, write_content_size=False) |
|
1156 | cctx = zstd.ZstdCompressor(level=1, write_content_size=False) | |
1141 |
empty = cctx.compress(b |
|
1157 | empty = cctx.compress(b"") | |
1142 |
|
1158 | |||
1143 | source = io.BytesIO(empty) |
|
1159 | source = io.BytesIO(empty) | |
1144 | source.seek(0) |
|
1160 | source.seek(0) | |
@@ -1157,24 +1173,28 b' class TestDecompressor_read_to_iter(unit' | |||||
1157 | def test_skip_bytes_too_large(self): |
|
1173 | def test_skip_bytes_too_large(self): | |
1158 | dctx = zstd.ZstdDecompressor() |
|
1174 | dctx = zstd.ZstdDecompressor() | |
1159 |
|
1175 | |||
1160 | with self.assertRaisesRegexp(ValueError, 'skip_bytes must be smaller than read_size'): |
|
1176 | with self.assertRaisesRegex( | |
1161 | b''.join(dctx.read_to_iter(b'', skip_bytes=1, read_size=1)) |
|
1177 | ValueError, "skip_bytes must be smaller than read_size" | |
|
1178 | ): | |||
|
1179 | b"".join(dctx.read_to_iter(b"", skip_bytes=1, read_size=1)) | |||
1162 |
|
1180 | |||
1163 | with self.assertRaisesRegexp(ValueError, 'skip_bytes larger than first input chunk'): |
|
1181 | with self.assertRaisesRegex( | |
1164 | b''.join(dctx.read_to_iter(b'foobar', skip_bytes=10)) |
|
1182 | ValueError, "skip_bytes larger than first input chunk" | |
|
1183 | ): | |||
|
1184 | b"".join(dctx.read_to_iter(b"foobar", skip_bytes=10)) | |||
1165 |
|
1185 | |||
1166 | def test_skip_bytes(self): |
|
1186 | def test_skip_bytes(self): | |
1167 | cctx = zstd.ZstdCompressor(write_content_size=False) |
|
1187 | cctx = zstd.ZstdCompressor(write_content_size=False) | |
1168 |
compressed = cctx.compress(b |
|
1188 | compressed = cctx.compress(b"foobar") | |
1169 |
|
1189 | |||
1170 | dctx = zstd.ZstdDecompressor() |
|
1190 | dctx = zstd.ZstdDecompressor() | |
1171 |
output = b |
|
1191 | output = b"".join(dctx.read_to_iter(b"hdr" + compressed, skip_bytes=3)) | |
1172 |
self.assertEqual(output, b |
|
1192 | self.assertEqual(output, b"foobar") | |
1173 |
|
1193 | |||
1174 | def test_large_output(self): |
|
1194 | def test_large_output(self): | |
1175 | source = io.BytesIO() |
|
1195 | source = io.BytesIO() | |
1176 |
source.write(b |
|
1196 | source.write(b"f" * zstd.DECOMPRESSION_RECOMMENDED_OUTPUT_SIZE) | |
1177 |
source.write(b |
|
1197 | source.write(b"o") | |
1178 | source.seek(0) |
|
1198 | source.seek(0) | |
1179 |
|
1199 | |||
1180 | cctx = zstd.ZstdCompressor(level=1) |
|
1200 | cctx = zstd.ZstdCompressor(level=1) | |
@@ -1191,7 +1211,7 b' class TestDecompressor_read_to_iter(unit' | |||||
1191 | with self.assertRaises(StopIteration): |
|
1211 | with self.assertRaises(StopIteration): | |
1192 | next(it) |
|
1212 | next(it) | |
1193 |
|
1213 | |||
1194 |
decompressed = b |
|
1214 | decompressed = b"".join(chunks) | |
1195 | self.assertEqual(decompressed, source.getvalue()) |
|
1215 | self.assertEqual(decompressed, source.getvalue()) | |
1196 |
|
1216 | |||
1197 | # And again with buffer protocol. |
|
1217 | # And again with buffer protocol. | |
@@ -1203,12 +1223,12 b' class TestDecompressor_read_to_iter(unit' | |||||
1203 | with self.assertRaises(StopIteration): |
|
1223 | with self.assertRaises(StopIteration): | |
1204 | next(it) |
|
1224 | next(it) | |
1205 |
|
1225 | |||
1206 |
decompressed = b |
|
1226 | decompressed = b"".join(chunks) | |
1207 | self.assertEqual(decompressed, source.getvalue()) |
|
1227 | self.assertEqual(decompressed, source.getvalue()) | |
1208 |
|
1228 | |||
1209 |
@unittest.skipUnless( |
|
1229 | @unittest.skipUnless("ZSTD_SLOW_TESTS" in os.environ, "ZSTD_SLOW_TESTS not set") | |
1210 | def test_large_input(self): |
|
1230 | def test_large_input(self): | |
1211 |
bytes = list(struct.Struct( |
|
1231 | bytes = list(struct.Struct(">B").pack(i) for i in range(256)) | |
1212 | compressed = NonClosingBytesIO() |
|
1232 | compressed = NonClosingBytesIO() | |
1213 | input_size = 0 |
|
1233 | input_size = 0 | |
1214 | cctx = zstd.ZstdCompressor(level=1) |
|
1234 | cctx = zstd.ZstdCompressor(level=1) | |
@@ -1217,14 +1237,18 b' class TestDecompressor_read_to_iter(unit' | |||||
1217 | compressor.write(random.choice(bytes)) |
|
1237 | compressor.write(random.choice(bytes)) | |
1218 | input_size += 1 |
|
1238 | input_size += 1 | |
1219 |
|
1239 | |||
1220 | have_compressed = len(compressed.getvalue()) > zstd.DECOMPRESSION_RECOMMENDED_INPUT_SIZE |
|
1240 | have_compressed = ( | |
|
1241 | len(compressed.getvalue()) | |||
|
1242 | > zstd.DECOMPRESSION_RECOMMENDED_INPUT_SIZE | |||
|
1243 | ) | |||
1221 | have_raw = input_size > zstd.DECOMPRESSION_RECOMMENDED_OUTPUT_SIZE * 2 |
|
1244 | have_raw = input_size > zstd.DECOMPRESSION_RECOMMENDED_OUTPUT_SIZE * 2 | |
1222 | if have_compressed and have_raw: |
|
1245 | if have_compressed and have_raw: | |
1223 | break |
|
1246 | break | |
1224 |
|
1247 | |||
1225 | compressed = io.BytesIO(compressed.getvalue()) |
|
1248 | compressed = io.BytesIO(compressed.getvalue()) | |
1226 |
self.assertGreater( |
|
1249 | self.assertGreater( | |
1227 |
|
|
1250 | len(compressed.getvalue()), zstd.DECOMPRESSION_RECOMMENDED_INPUT_SIZE | |
|
1251 | ) | |||
1228 |
|
1252 | |||
1229 | dctx = zstd.ZstdDecompressor() |
|
1253 | dctx = zstd.ZstdDecompressor() | |
1230 | it = dctx.read_to_iter(compressed) |
|
1254 | it = dctx.read_to_iter(compressed) | |
@@ -1237,7 +1261,7 b' class TestDecompressor_read_to_iter(unit' | |||||
1237 | with self.assertRaises(StopIteration): |
|
1261 | with self.assertRaises(StopIteration): | |
1238 | next(it) |
|
1262 | next(it) | |
1239 |
|
1263 | |||
1240 |
decompressed = b |
|
1264 | decompressed = b"".join(chunks) | |
1241 | self.assertEqual(len(decompressed), input_size) |
|
1265 | self.assertEqual(len(decompressed), input_size) | |
1242 |
|
1266 | |||
1243 | # And again with buffer protocol. |
|
1267 | # And again with buffer protocol. | |
@@ -1251,7 +1275,7 b' class TestDecompressor_read_to_iter(unit' | |||||
1251 | with self.assertRaises(StopIteration): |
|
1275 | with self.assertRaises(StopIteration): | |
1252 | next(it) |
|
1276 | next(it) | |
1253 |
|
1277 | |||
1254 |
decompressed = b |
|
1278 | decompressed = b"".join(chunks) | |
1255 | self.assertEqual(len(decompressed), input_size) |
|
1279 | self.assertEqual(len(decompressed), input_size) | |
1256 |
|
1280 | |||
1257 | def test_interesting(self): |
|
1281 | def test_interesting(self): | |
@@ -1263,22 +1287,23 b' class TestDecompressor_read_to_iter(unit' | |||||
1263 | compressed = NonClosingBytesIO() |
|
1287 | compressed = NonClosingBytesIO() | |
1264 | with cctx.stream_writer(compressed) as compressor: |
|
1288 | with cctx.stream_writer(compressed) as compressor: | |
1265 | for i in range(256): |
|
1289 | for i in range(256): | |
1266 |
chunk = b |
|
1290 | chunk = b"\0" * 1024 | |
1267 | compressor.write(chunk) |
|
1291 | compressor.write(chunk) | |
1268 | source.write(chunk) |
|
1292 | source.write(chunk) | |
1269 |
|
1293 | |||
1270 | dctx = zstd.ZstdDecompressor() |
|
1294 | dctx = zstd.ZstdDecompressor() | |
1271 |
|
1295 | |||
1272 |
simple = dctx.decompress( |
|
1296 | simple = dctx.decompress( | |
1273 |
|
|
1297 | compressed.getvalue(), max_output_size=len(source.getvalue()) | |
|
1298 | ) | |||
1274 | self.assertEqual(simple, source.getvalue()) |
|
1299 | self.assertEqual(simple, source.getvalue()) | |
1275 |
|
1300 | |||
1276 | compressed = io.BytesIO(compressed.getvalue()) |
|
1301 | compressed = io.BytesIO(compressed.getvalue()) | |
1277 |
streamed = b |
|
1302 | streamed = b"".join(dctx.read_to_iter(compressed)) | |
1278 | self.assertEqual(streamed, source.getvalue()) |
|
1303 | self.assertEqual(streamed, source.getvalue()) | |
1279 |
|
1304 | |||
1280 | def test_read_write_size(self): |
|
1305 | def test_read_write_size(self): | |
1281 |
source = OpCountingBytesIO(zstd.ZstdCompressor().compress(b |
|
1306 | source = OpCountingBytesIO(zstd.ZstdCompressor().compress(b"foobarfoobar")) | |
1282 | dctx = zstd.ZstdDecompressor() |
|
1307 | dctx = zstd.ZstdDecompressor() | |
1283 | for chunk in dctx.read_to_iter(source, read_size=1, write_size=1): |
|
1308 | for chunk in dctx.read_to_iter(source, read_size=1, write_size=1): | |
1284 | self.assertEqual(len(chunk), 1) |
|
1309 | self.assertEqual(len(chunk), 1) | |
@@ -1287,97 +1312,110 b' class TestDecompressor_read_to_iter(unit' | |||||
1287 |
|
1312 | |||
1288 | def test_magic_less(self): |
|
1313 | def test_magic_less(self): | |
1289 | params = zstd.CompressionParameters.from_level( |
|
1314 | params = zstd.CompressionParameters.from_level( | |
1290 |
1, format=zstd.FORMAT_ZSTD1_MAGICLESS |
|
1315 | 1, format=zstd.FORMAT_ZSTD1_MAGICLESS | |
|
1316 | ) | |||
1291 | cctx = zstd.ZstdCompressor(compression_params=params) |
|
1317 | cctx = zstd.ZstdCompressor(compression_params=params) | |
1292 |
frame = cctx.compress(b |
|
1318 | frame = cctx.compress(b"foobar") | |
1293 |
|
1319 | |||
1294 |
self.assertNotEqual(frame[0:4], b |
|
1320 | self.assertNotEqual(frame[0:4], b"\x28\xb5\x2f\xfd") | |
1295 |
|
1321 | |||
1296 | dctx = zstd.ZstdDecompressor() |
|
1322 | dctx = zstd.ZstdDecompressor() | |
1297 |
with self.assertRaisesRegex |
|
1323 | with self.assertRaisesRegex( | |
1298 |
zstd.ZstdError, |
|
1324 | zstd.ZstdError, "error determining content size from frame header" | |
|
1325 | ): | |||
1299 | dctx.decompress(frame) |
|
1326 | dctx.decompress(frame) | |
1300 |
|
1327 | |||
1301 | dctx = zstd.ZstdDecompressor(format=zstd.FORMAT_ZSTD1_MAGICLESS) |
|
1328 | dctx = zstd.ZstdDecompressor(format=zstd.FORMAT_ZSTD1_MAGICLESS) | |
1302 |
res = b |
|
1329 | res = b"".join(dctx.read_to_iter(frame)) | |
1303 |
self.assertEqual(res, b |
|
1330 | self.assertEqual(res, b"foobar") | |
1304 |
|
1331 | |||
1305 |
|
1332 | |||
1306 | @make_cffi |
|
1333 | @make_cffi | |
1307 |
class TestDecompressor_content_dict_chain( |
|
1334 | class TestDecompressor_content_dict_chain(TestCase): | |
1308 | def test_bad_inputs_simple(self): |
|
1335 | def test_bad_inputs_simple(self): | |
1309 | dctx = zstd.ZstdDecompressor() |
|
1336 | dctx = zstd.ZstdDecompressor() | |
1310 |
|
1337 | |||
1311 | with self.assertRaises(TypeError): |
|
1338 | with self.assertRaises(TypeError): | |
1312 |
dctx.decompress_content_dict_chain(b |
|
1339 | dctx.decompress_content_dict_chain(b"foo") | |
1313 |
|
1340 | |||
1314 | with self.assertRaises(TypeError): |
|
1341 | with self.assertRaises(TypeError): | |
1315 |
dctx.decompress_content_dict_chain((b |
|
1342 | dctx.decompress_content_dict_chain((b"foo", b"bar")) | |
1316 |
|
1343 | |||
1317 |
with self.assertRaisesRegex |
|
1344 | with self.assertRaisesRegex(ValueError, "empty input chain"): | |
1318 | dctx.decompress_content_dict_chain([]) |
|
1345 | dctx.decompress_content_dict_chain([]) | |
1319 |
|
1346 | |||
1320 |
with self.assertRaisesRegex |
|
1347 | with self.assertRaisesRegex(ValueError, "chunk 0 must be bytes"): | |
1321 |
dctx.decompress_content_dict_chain([u |
|
1348 | dctx.decompress_content_dict_chain([u"foo"]) | |
1322 |
|
1349 | |||
1323 |
with self.assertRaisesRegex |
|
1350 | with self.assertRaisesRegex(ValueError, "chunk 0 must be bytes"): | |
1324 | dctx.decompress_content_dict_chain([True]) |
|
1351 | dctx.decompress_content_dict_chain([True]) | |
1325 |
|
1352 | |||
1326 | with self.assertRaisesRegexp(ValueError, 'chunk 0 is too small to contain a zstd frame'): |
|
1353 | with self.assertRaisesRegex( | |
|
1354 | ValueError, "chunk 0 is too small to contain a zstd frame" | |||
|
1355 | ): | |||
1327 | dctx.decompress_content_dict_chain([zstd.FRAME_HEADER]) |
|
1356 | dctx.decompress_content_dict_chain([zstd.FRAME_HEADER]) | |
1328 |
|
1357 | |||
1329 |
with self.assertRaisesRegex |
|
1358 | with self.assertRaisesRegex(ValueError, "chunk 0 is not a valid zstd frame"): | |
1330 |
dctx.decompress_content_dict_chain([b |
|
1359 | dctx.decompress_content_dict_chain([b"foo" * 8]) | |
1331 |
|
1360 | |||
1332 |
no_size = zstd.ZstdCompressor(write_content_size=False).compress(b |
|
1361 | no_size = zstd.ZstdCompressor(write_content_size=False).compress(b"foo" * 64) | |
1333 |
|
1362 | |||
1334 | with self.assertRaisesRegexp(ValueError, 'chunk 0 missing content size in frame'): |
|
1363 | with self.assertRaisesRegex( | |
|
1364 | ValueError, "chunk 0 missing content size in frame" | |||
|
1365 | ): | |||
1335 | dctx.decompress_content_dict_chain([no_size]) |
|
1366 | dctx.decompress_content_dict_chain([no_size]) | |
1336 |
|
1367 | |||
1337 | # Corrupt first frame. |
|
1368 | # Corrupt first frame. | |
1338 |
frame = zstd.ZstdCompressor().compress(b |
|
1369 | frame = zstd.ZstdCompressor().compress(b"foo" * 64) | |
1339 | frame = frame[0:12] + frame[15:] |
|
1370 | frame = frame[0:12] + frame[15:] | |
1340 |
with self.assertRaisesRegex |
|
1371 | with self.assertRaisesRegex( | |
1341 |
|
|
1372 | zstd.ZstdError, "chunk 0 did not decompress full frame" | |
|
1373 | ): | |||
1342 | dctx.decompress_content_dict_chain([frame]) |
|
1374 | dctx.decompress_content_dict_chain([frame]) | |
1343 |
|
1375 | |||
1344 | def test_bad_subsequent_input(self): |
|
1376 | def test_bad_subsequent_input(self): | |
1345 |
initial = zstd.ZstdCompressor().compress(b |
|
1377 | initial = zstd.ZstdCompressor().compress(b"foo" * 64) | |
1346 |
|
1378 | |||
1347 | dctx = zstd.ZstdDecompressor() |
|
1379 | dctx = zstd.ZstdDecompressor() | |
1348 |
|
1380 | |||
1349 |
with self.assertRaisesRegex |
|
1381 | with self.assertRaisesRegex(ValueError, "chunk 1 must be bytes"): | |
1350 |
dctx.decompress_content_dict_chain([initial, u |
|
1382 | dctx.decompress_content_dict_chain([initial, u"foo"]) | |
1351 |
|
1383 | |||
1352 |
with self.assertRaisesRegex |
|
1384 | with self.assertRaisesRegex(ValueError, "chunk 1 must be bytes"): | |
1353 | dctx.decompress_content_dict_chain([initial, None]) |
|
1385 | dctx.decompress_content_dict_chain([initial, None]) | |
1354 |
|
1386 | |||
1355 | with self.assertRaisesRegexp(ValueError, 'chunk 1 is too small to contain a zstd frame'): |
|
1387 | with self.assertRaisesRegex( | |
|
1388 | ValueError, "chunk 1 is too small to contain a zstd frame" | |||
|
1389 | ): | |||
1356 | dctx.decompress_content_dict_chain([initial, zstd.FRAME_HEADER]) |
|
1390 | dctx.decompress_content_dict_chain([initial, zstd.FRAME_HEADER]) | |
1357 |
|
1391 | |||
1358 |
with self.assertRaisesRegex |
|
1392 | with self.assertRaisesRegex(ValueError, "chunk 1 is not a valid zstd frame"): | |
1359 |
dctx.decompress_content_dict_chain([initial, b |
|
1393 | dctx.decompress_content_dict_chain([initial, b"foo" * 8]) | |
1360 |
|
1394 | |||
1361 |
no_size = zstd.ZstdCompressor(write_content_size=False).compress(b |
|
1395 | no_size = zstd.ZstdCompressor(write_content_size=False).compress(b"foo" * 64) | |
1362 |
|
1396 | |||
1363 | with self.assertRaisesRegexp(ValueError, 'chunk 1 missing content size in frame'): |
|
1397 | with self.assertRaisesRegex( | |
|
1398 | ValueError, "chunk 1 missing content size in frame" | |||
|
1399 | ): | |||
1364 | dctx.decompress_content_dict_chain([initial, no_size]) |
|
1400 | dctx.decompress_content_dict_chain([initial, no_size]) | |
1365 |
|
1401 | |||
1366 | # Corrupt second frame. |
|
1402 | # Corrupt second frame. | |
1367 |
cctx = zstd.ZstdCompressor(dict_data=zstd.ZstdCompressionDict(b |
|
1403 | cctx = zstd.ZstdCompressor(dict_data=zstd.ZstdCompressionDict(b"foo" * 64)) | |
1368 |
frame = cctx.compress(b |
|
1404 | frame = cctx.compress(b"bar" * 64) | |
1369 | frame = frame[0:12] + frame[15:] |
|
1405 | frame = frame[0:12] + frame[15:] | |
1370 |
|
1406 | |||
1371 | with self.assertRaisesRegexp(zstd.ZstdError, 'chunk 1 did not decompress full frame'): |
|
1407 | with self.assertRaisesRegex( | |
|
1408 | zstd.ZstdError, "chunk 1 did not decompress full frame" | |||
|
1409 | ): | |||
1372 | dctx.decompress_content_dict_chain([initial, frame]) |
|
1410 | dctx.decompress_content_dict_chain([initial, frame]) | |
1373 |
|
1411 | |||
1374 | def test_simple(self): |
|
1412 | def test_simple(self): | |
1375 | original = [ |
|
1413 | original = [ | |
1376 |
b |
|
1414 | b"foo" * 64, | |
1377 |
b |
|
1415 | b"foobar" * 64, | |
1378 |
b |
|
1416 | b"baz" * 64, | |
1379 |
b |
|
1417 | b"foobaz" * 64, | |
1380 |
b |
|
1418 | b"foobarbaz" * 64, | |
1381 | ] |
|
1419 | ] | |
1382 |
|
1420 | |||
1383 | chunks = [] |
|
1421 | chunks = [] | |
@@ -1396,12 +1434,12 b' class TestDecompressor_content_dict_chai' | |||||
1396 |
|
1434 | |||
1397 |
|
1435 | |||
1398 | # TODO enable for CFFI |
|
1436 | # TODO enable for CFFI | |
1399 |
class TestDecompressor_multi_decompress_to_buffer( |
|
1437 | class TestDecompressor_multi_decompress_to_buffer(TestCase): | |
1400 | def test_invalid_inputs(self): |
|
1438 | def test_invalid_inputs(self): | |
1401 | dctx = zstd.ZstdDecompressor() |
|
1439 | dctx = zstd.ZstdDecompressor() | |
1402 |
|
1440 | |||
1403 |
if not hasattr(dctx, |
|
1441 | if not hasattr(dctx, "multi_decompress_to_buffer"): | |
1404 |
self.skipTest( |
|
1442 | self.skipTest("multi_decompress_to_buffer not available") | |
1405 |
|
1443 | |||
1406 | with self.assertRaises(TypeError): |
|
1444 | with self.assertRaises(TypeError): | |
1407 | dctx.multi_decompress_to_buffer(True) |
|
1445 | dctx.multi_decompress_to_buffer(True) | |
@@ -1409,22 +1447,24 b' class TestDecompressor_multi_decompress_' | |||||
1409 | with self.assertRaises(TypeError): |
|
1447 | with self.assertRaises(TypeError): | |
1410 | dctx.multi_decompress_to_buffer((1, 2)) |
|
1448 | dctx.multi_decompress_to_buffer((1, 2)) | |
1411 |
|
1449 | |||
1412 |
with self.assertRaisesRegex |
|
1450 | with self.assertRaisesRegex(TypeError, "item 0 not a bytes like object"): | |
1413 |
dctx.multi_decompress_to_buffer([u |
|
1451 | dctx.multi_decompress_to_buffer([u"foo"]) | |
1414 |
|
1452 | |||
1415 | with self.assertRaisesRegexp(ValueError, 'could not determine decompressed size of item 0'): |
|
1453 | with self.assertRaisesRegex( | |
1416 | dctx.multi_decompress_to_buffer([b'foobarbaz']) |
|
1454 | ValueError, "could not determine decompressed size of item 0" | |
|
1455 | ): | |||
|
1456 | dctx.multi_decompress_to_buffer([b"foobarbaz"]) | |||
1417 |
|
1457 | |||
1418 | def test_list_input(self): |
|
1458 | def test_list_input(self): | |
1419 | cctx = zstd.ZstdCompressor() |
|
1459 | cctx = zstd.ZstdCompressor() | |
1420 |
|
1460 | |||
1421 |
original = [b |
|
1461 | original = [b"foo" * 4, b"bar" * 6] | |
1422 | frames = [cctx.compress(d) for d in original] |
|
1462 | frames = [cctx.compress(d) for d in original] | |
1423 |
|
1463 | |||
1424 | dctx = zstd.ZstdDecompressor() |
|
1464 | dctx = zstd.ZstdDecompressor() | |
1425 |
|
1465 | |||
1426 |
if not hasattr(dctx, |
|
1466 | if not hasattr(dctx, "multi_decompress_to_buffer"): | |
1427 |
self.skipTest( |
|
1467 | self.skipTest("multi_decompress_to_buffer not available") | |
1428 |
|
1468 | |||
1429 | result = dctx.multi_decompress_to_buffer(frames) |
|
1469 | result = dctx.multi_decompress_to_buffer(frames) | |
1430 |
|
1470 | |||
@@ -1442,14 +1482,14 b' class TestDecompressor_multi_decompress_' | |||||
1442 | def test_list_input_frame_sizes(self): |
|
1482 | def test_list_input_frame_sizes(self): | |
1443 | cctx = zstd.ZstdCompressor() |
|
1483 | cctx = zstd.ZstdCompressor() | |
1444 |
|
1484 | |||
1445 |
original = [b |
|
1485 | original = [b"foo" * 4, b"bar" * 6, b"baz" * 8] | |
1446 | frames = [cctx.compress(d) for d in original] |
|
1486 | frames = [cctx.compress(d) for d in original] | |
1447 |
sizes = struct.pack( |
|
1487 | sizes = struct.pack("=" + "Q" * len(original), *map(len, original)) | |
1448 |
|
1488 | |||
1449 | dctx = zstd.ZstdDecompressor() |
|
1489 | dctx = zstd.ZstdDecompressor() | |
1450 |
|
1490 | |||
1451 |
if not hasattr(dctx, |
|
1491 | if not hasattr(dctx, "multi_decompress_to_buffer"): | |
1452 |
self.skipTest( |
|
1492 | self.skipTest("multi_decompress_to_buffer not available") | |
1453 |
|
1493 | |||
1454 | result = dctx.multi_decompress_to_buffer(frames, decompressed_sizes=sizes) |
|
1494 | result = dctx.multi_decompress_to_buffer(frames, decompressed_sizes=sizes) | |
1455 |
|
1495 | |||
@@ -1462,16 +1502,18 b' class TestDecompressor_multi_decompress_' | |||||
1462 | def test_buffer_with_segments_input(self): |
|
1502 | def test_buffer_with_segments_input(self): | |
1463 | cctx = zstd.ZstdCompressor() |
|
1503 | cctx = zstd.ZstdCompressor() | |
1464 |
|
1504 | |||
1465 |
original = [b |
|
1505 | original = [b"foo" * 4, b"bar" * 6] | |
1466 | frames = [cctx.compress(d) for d in original] |
|
1506 | frames = [cctx.compress(d) for d in original] | |
1467 |
|
1507 | |||
1468 | dctx = zstd.ZstdDecompressor() |
|
1508 | dctx = zstd.ZstdDecompressor() | |
1469 |
|
1509 | |||
1470 |
if not hasattr(dctx, |
|
1510 | if not hasattr(dctx, "multi_decompress_to_buffer"): | |
1471 |
self.skipTest( |
|
1511 | self.skipTest("multi_decompress_to_buffer not available") | |
1472 |
|
1512 | |||
1473 | segments = struct.pack('=QQQQ', 0, len(frames[0]), len(frames[0]), len(frames[1])) |
|
1513 | segments = struct.pack( | |
1474 | b = zstd.BufferWithSegments(b''.join(frames), segments) |
|
1514 | "=QQQQ", 0, len(frames[0]), len(frames[0]), len(frames[1]) | |
|
1515 | ) | |||
|
1516 | b = zstd.BufferWithSegments(b"".join(frames), segments) | |||
1475 |
|
1517 | |||
1476 | result = dctx.multi_decompress_to_buffer(b) |
|
1518 | result = dctx.multi_decompress_to_buffer(b) | |
1477 |
|
1519 | |||
@@ -1483,19 +1525,25 b' class TestDecompressor_multi_decompress_' | |||||
1483 |
|
1525 | |||
1484 | def test_buffer_with_segments_sizes(self): |
|
1526 | def test_buffer_with_segments_sizes(self): | |
1485 | cctx = zstd.ZstdCompressor(write_content_size=False) |
|
1527 | cctx = zstd.ZstdCompressor(write_content_size=False) | |
1486 |
original = [b |
|
1528 | original = [b"foo" * 4, b"bar" * 6, b"baz" * 8] | |
1487 | frames = [cctx.compress(d) for d in original] |
|
1529 | frames = [cctx.compress(d) for d in original] | |
1488 |
sizes = struct.pack( |
|
1530 | sizes = struct.pack("=" + "Q" * len(original), *map(len, original)) | |
1489 |
|
1531 | |||
1490 | dctx = zstd.ZstdDecompressor() |
|
1532 | dctx = zstd.ZstdDecompressor() | |
1491 |
|
1533 | |||
1492 |
if not hasattr(dctx, |
|
1534 | if not hasattr(dctx, "multi_decompress_to_buffer"): | |
1493 |
self.skipTest( |
|
1535 | self.skipTest("multi_decompress_to_buffer not available") | |
1494 |
|
1536 | |||
1495 |
segments = struct.pack( |
|
1537 | segments = struct.pack( | |
1496 | len(frames[0]), len(frames[1]), |
|
1538 | "=QQQQQQ", | |
1497 | len(frames[0]) + len(frames[1]), len(frames[2])) |
|
1539 | 0, | |
1498 | b = zstd.BufferWithSegments(b''.join(frames), segments) |
|
1540 | len(frames[0]), | |
|
1541 | len(frames[0]), | |||
|
1542 | len(frames[1]), | |||
|
1543 | len(frames[0]) + len(frames[1]), | |||
|
1544 | len(frames[2]), | |||
|
1545 | ) | |||
|
1546 | b = zstd.BufferWithSegments(b"".join(frames), segments) | |||
1499 |
|
1547 | |||
1500 | result = dctx.multi_decompress_to_buffer(b, decompressed_sizes=sizes) |
|
1548 | result = dctx.multi_decompress_to_buffer(b, decompressed_sizes=sizes) | |
1501 |
|
1549 | |||
@@ -1509,15 +1557,15 b' class TestDecompressor_multi_decompress_' | |||||
1509 | cctx = zstd.ZstdCompressor() |
|
1557 | cctx = zstd.ZstdCompressor() | |
1510 |
|
1558 | |||
1511 | original = [ |
|
1559 | original = [ | |
1512 |
b |
|
1560 | b"foo0" * 2, | |
1513 |
b |
|
1561 | b"foo1" * 3, | |
1514 |
b |
|
1562 | b"foo2" * 4, | |
1515 |
b |
|
1563 | b"foo3" * 5, | |
1516 |
b |
|
1564 | b"foo4" * 6, | |
1517 | ] |
|
1565 | ] | |
1518 |
|
1566 | |||
1519 |
if not hasattr(cctx, |
|
1567 | if not hasattr(cctx, "multi_compress_to_buffer"): | |
1520 |
self.skipTest( |
|
1568 | self.skipTest("multi_compress_to_buffer not available") | |
1521 |
|
1569 | |||
1522 | frames = cctx.multi_compress_to_buffer(original) |
|
1570 | frames = cctx.multi_compress_to_buffer(original) | |
1523 |
|
1571 | |||
@@ -1532,16 +1580,24 b' class TestDecompressor_multi_decompress_' | |||||
1532 | self.assertEqual(data, decompressed[i].tobytes()) |
|
1580 | self.assertEqual(data, decompressed[i].tobytes()) | |
1533 |
|
1581 | |||
1534 | # And a manual mode. |
|
1582 | # And a manual mode. | |
1535 |
b = b |
|
1583 | b = b"".join([frames[0].tobytes(), frames[1].tobytes()]) | |
1536 |
b1 = zstd.BufferWithSegments( |
|
1584 | b1 = zstd.BufferWithSegments( | |
1537 | 0, len(frames[0]), |
|
1585 | b, struct.pack("=QQQQ", 0, len(frames[0]), len(frames[0]), len(frames[1])) | |
1538 | len(frames[0]), len(frames[1]))) |
|
1586 | ) | |
1539 |
|
1587 | |||
1540 |
b = b |
|
1588 | b = b"".join([frames[2].tobytes(), frames[3].tobytes(), frames[4].tobytes()]) | |
1541 |
b2 = zstd.BufferWithSegments( |
|
1589 | b2 = zstd.BufferWithSegments( | |
1542 | 0, len(frames[2]), |
|
1590 | b, | |
1543 | len(frames[2]), len(frames[3]), |
|
1591 | struct.pack( | |
1544 | len(frames[2]) + len(frames[3]), len(frames[4]))) |
|
1592 | "=QQQQQQ", | |
|
1593 | 0, | |||
|
1594 | len(frames[2]), | |||
|
1595 | len(frames[2]), | |||
|
1596 | len(frames[3]), | |||
|
1597 | len(frames[2]) + len(frames[3]), | |||
|
1598 | len(frames[4]), | |||
|
1599 | ), | |||
|
1600 | ) | |||
1545 |
|
1601 | |||
1546 | c = zstd.BufferWithSegmentsCollection(b1, b2) |
|
1602 | c = zstd.BufferWithSegmentsCollection(b1, b2) | |
1547 |
|
1603 | |||
@@ -1560,8 +1616,8 b' class TestDecompressor_multi_decompress_' | |||||
1560 |
|
1616 | |||
1561 | dctx = zstd.ZstdDecompressor(dict_data=d) |
|
1617 | dctx = zstd.ZstdDecompressor(dict_data=d) | |
1562 |
|
1618 | |||
1563 |
if not hasattr(dctx, |
|
1619 | if not hasattr(dctx, "multi_decompress_to_buffer"): | |
1564 |
self.skipTest( |
|
1620 | self.skipTest("multi_decompress_to_buffer not available") | |
1565 |
|
1621 | |||
1566 | result = dctx.multi_decompress_to_buffer(frames) |
|
1622 | result = dctx.multi_decompress_to_buffer(frames) | |
1567 |
|
1623 | |||
@@ -1571,41 +1627,44 b' class TestDecompressor_multi_decompress_' | |||||
1571 | cctx = zstd.ZstdCompressor() |
|
1627 | cctx = zstd.ZstdCompressor() | |
1572 |
|
1628 | |||
1573 | frames = [] |
|
1629 | frames = [] | |
1574 |
frames.extend(cctx.compress(b |
|
1630 | frames.extend(cctx.compress(b"x" * 64) for i in range(256)) | |
1575 |
frames.extend(cctx.compress(b |
|
1631 | frames.extend(cctx.compress(b"y" * 64) for i in range(256)) | |
1576 |
|
1632 | |||
1577 | dctx = zstd.ZstdDecompressor() |
|
1633 | dctx = zstd.ZstdDecompressor() | |
1578 |
|
1634 | |||
1579 |
if not hasattr(dctx, |
|
1635 | if not hasattr(dctx, "multi_decompress_to_buffer"): | |
1580 |
self.skipTest( |
|
1636 | self.skipTest("multi_decompress_to_buffer not available") | |
1581 |
|
1637 | |||
1582 | result = dctx.multi_decompress_to_buffer(frames, threads=-1) |
|
1638 | result = dctx.multi_decompress_to_buffer(frames, threads=-1) | |
1583 |
|
1639 | |||
1584 | self.assertEqual(len(result), len(frames)) |
|
1640 | self.assertEqual(len(result), len(frames)) | |
1585 | self.assertEqual(result.size(), 2 * 64 * 256) |
|
1641 | self.assertEqual(result.size(), 2 * 64 * 256) | |
1586 |
self.assertEqual(result[0].tobytes(), b |
|
1642 | self.assertEqual(result[0].tobytes(), b"x" * 64) | |
1587 |
self.assertEqual(result[256].tobytes(), b |
|
1643 | self.assertEqual(result[256].tobytes(), b"y" * 64) | |
1588 |
|
1644 | |||
1589 | def test_item_failure(self): |
|
1645 | def test_item_failure(self): | |
1590 | cctx = zstd.ZstdCompressor() |
|
1646 | cctx = zstd.ZstdCompressor() | |
1591 |
frames = [cctx.compress(b |
|
1647 | frames = [cctx.compress(b"x" * 128), cctx.compress(b"y" * 128)] | |
1592 |
|
1648 | |||
1593 |
frames[1] = frames[1][0:15] + b |
|
1649 | frames[1] = frames[1][0:15] + b"extra" + frames[1][15:] | |
1594 |
|
1650 | |||
1595 | dctx = zstd.ZstdDecompressor() |
|
1651 | dctx = zstd.ZstdDecompressor() | |
1596 |
|
1652 | |||
1597 |
if not hasattr(dctx, |
|
1653 | if not hasattr(dctx, "multi_decompress_to_buffer"): | |
1598 |
self.skipTest( |
|
1654 | self.skipTest("multi_decompress_to_buffer not available") | |
1599 |
|
1655 | |||
1600 |
with self.assertRaisesRegex |
|
1656 | with self.assertRaisesRegex( | |
1601 | 'error decompressing item 1: (' |
|
1657 | zstd.ZstdError, | |
1602 | 'Corrupted block|' |
|
1658 | "error decompressing item 1: (" | |
1603 | 'Destination buffer is too small)'): |
|
1659 | "Corrupted block|" | |
|
1660 | "Destination buffer is too small)", | |||
|
1661 | ): | |||
1604 | dctx.multi_decompress_to_buffer(frames) |
|
1662 | dctx.multi_decompress_to_buffer(frames) | |
1605 |
|
1663 | |||
1606 |
with self.assertRaisesRegex |
|
1664 | with self.assertRaisesRegex( | |
1607 | 'error decompressing item 1: (' |
|
1665 | zstd.ZstdError, | |
1608 | 'Corrupted block|' |
|
1666 | "error decompressing item 1: (" | |
1609 | 'Destination buffer is too small)'): |
|
1667 | "Corrupted block|" | |
|
1668 | "Destination buffer is too small)", | |||
|
1669 | ): | |||
1610 | dctx.multi_decompress_to_buffer(frames, threads=2) |
|
1670 | dctx.multi_decompress_to_buffer(frames, threads=2) | |
1611 |
|
@@ -6,29 +6,37 b' try:' | |||||
6 | import hypothesis |
|
6 | import hypothesis | |
7 | import hypothesis.strategies as strategies |
|
7 | import hypothesis.strategies as strategies | |
8 | except ImportError: |
|
8 | except ImportError: | |
9 |
raise unittest.SkipTest( |
|
9 | raise unittest.SkipTest("hypothesis not available") | |
10 |
|
10 | |||
11 | import zstandard as zstd |
|
11 | import zstandard as zstd | |
12 |
|
12 | |||
13 |
from . |
|
13 | from .common import ( | |
14 | make_cffi, |
|
14 | make_cffi, | |
15 | NonClosingBytesIO, |
|
15 | NonClosingBytesIO, | |
16 | random_input_data, |
|
16 | random_input_data, | |
|
17 | TestCase, | |||
17 | ) |
|
18 | ) | |
18 |
|
19 | |||
19 |
|
20 | |||
20 |
@unittest.skipUnless( |
|
21 | @unittest.skipUnless("ZSTD_SLOW_TESTS" in os.environ, "ZSTD_SLOW_TESTS not set") | |
21 | @make_cffi |
|
22 | @make_cffi | |
22 |
class TestDecompressor_stream_reader_fuzzing( |
|
23 | class TestDecompressor_stream_reader_fuzzing(TestCase): | |
23 | @hypothesis.settings( |
|
24 | @hypothesis.settings( | |
24 | suppress_health_check=[hypothesis.HealthCheck.large_base_example]) |
|
25 | suppress_health_check=[ | |
25 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
26 | hypothesis.HealthCheck.large_base_example, | |
26 | level=strategies.integers(min_value=1, max_value=5), |
|
27 | hypothesis.HealthCheck.too_slow, | |
27 | streaming=strategies.booleans(), |
|
28 | ] | |
28 | source_read_size=strategies.integers(1, 1048576), |
|
29 | ) | |
29 | read_sizes=strategies.data()) |
|
30 | @hypothesis.given( | |
30 | def test_stream_source_read_variance(self, original, level, streaming, |
|
31 | original=strategies.sampled_from(random_input_data()), | |
31 | source_read_size, read_sizes): |
|
32 | level=strategies.integers(min_value=1, max_value=5), | |
|
33 | streaming=strategies.booleans(), | |||
|
34 | source_read_size=strategies.integers(1, 1048576), | |||
|
35 | read_sizes=strategies.data(), | |||
|
36 | ) | |||
|
37 | def test_stream_source_read_variance( | |||
|
38 | self, original, level, streaming, source_read_size, read_sizes | |||
|
39 | ): | |||
32 | cctx = zstd.ZstdCompressor(level=level) |
|
40 | cctx = zstd.ZstdCompressor(level=level) | |
33 |
|
41 | |||
34 | if streaming: |
|
42 | if streaming: | |
@@ -53,18 +61,22 b' class TestDecompressor_stream_reader_fuz' | |||||
53 |
|
61 | |||
54 | chunks.append(chunk) |
|
62 | chunks.append(chunk) | |
55 |
|
63 | |||
56 |
self.assertEqual(b |
|
64 | self.assertEqual(b"".join(chunks), original) | |
57 |
|
65 | |||
58 | # Similar to above except we have a constant read() size. |
|
66 | # Similar to above except we have a constant read() size. | |
59 | @hypothesis.settings( |
|
67 | @hypothesis.settings( | |
60 |
suppress_health_check=[hypothesis.HealthCheck.large_base_example] |
|
68 | suppress_health_check=[hypothesis.HealthCheck.large_base_example] | |
61 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
69 | ) | |
62 | level=strategies.integers(min_value=1, max_value=5), |
|
70 | @hypothesis.given( | |
63 | streaming=strategies.booleans(), |
|
71 | original=strategies.sampled_from(random_input_data()), | |
64 | source_read_size=strategies.integers(1, 1048576), |
|
72 | level=strategies.integers(min_value=1, max_value=5), | |
65 | read_size=strategies.integers(-1, 131072)) |
|
73 | streaming=strategies.booleans(), | |
66 | def test_stream_source_read_size(self, original, level, streaming, |
|
74 | source_read_size=strategies.integers(1, 1048576), | |
67 | source_read_size, read_size): |
|
75 | read_size=strategies.integers(-1, 131072), | |
|
76 | ) | |||
|
77 | def test_stream_source_read_size( | |||
|
78 | self, original, level, streaming, source_read_size, read_size | |||
|
79 | ): | |||
68 | if read_size == 0: |
|
80 | if read_size == 0: | |
69 | read_size = 1 |
|
81 | read_size = 1 | |
70 |
|
82 | |||
@@ -91,17 +103,24 b' class TestDecompressor_stream_reader_fuz' | |||||
91 |
|
103 | |||
92 | chunks.append(chunk) |
|
104 | chunks.append(chunk) | |
93 |
|
105 | |||
94 |
self.assertEqual(b |
|
106 | self.assertEqual(b"".join(chunks), original) | |
95 |
|
107 | |||
96 | @hypothesis.settings( |
|
108 | @hypothesis.settings( | |
97 | suppress_health_check=[hypothesis.HealthCheck.large_base_example]) |
|
109 | suppress_health_check=[ | |
98 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
110 | hypothesis.HealthCheck.large_base_example, | |
99 | level=strategies.integers(min_value=1, max_value=5), |
|
111 | hypothesis.HealthCheck.too_slow, | |
100 | streaming=strategies.booleans(), |
|
112 | ] | |
101 | source_read_size=strategies.integers(1, 1048576), |
|
113 | ) | |
102 | read_sizes=strategies.data()) |
|
114 | @hypothesis.given( | |
103 | def test_buffer_source_read_variance(self, original, level, streaming, |
|
115 | original=strategies.sampled_from(random_input_data()), | |
104 | source_read_size, read_sizes): |
|
116 | level=strategies.integers(min_value=1, max_value=5), | |
|
117 | streaming=strategies.booleans(), | |||
|
118 | source_read_size=strategies.integers(1, 1048576), | |||
|
119 | read_sizes=strategies.data(), | |||
|
120 | ) | |||
|
121 | def test_buffer_source_read_variance( | |||
|
122 | self, original, level, streaming, source_read_size, read_sizes | |||
|
123 | ): | |||
105 | cctx = zstd.ZstdCompressor(level=level) |
|
124 | cctx = zstd.ZstdCompressor(level=level) | |
106 |
|
125 | |||
107 | if streaming: |
|
126 | if streaming: | |
@@ -125,18 +144,22 b' class TestDecompressor_stream_reader_fuz' | |||||
125 |
|
144 | |||
126 | chunks.append(chunk) |
|
145 | chunks.append(chunk) | |
127 |
|
146 | |||
128 |
self.assertEqual(b |
|
147 | self.assertEqual(b"".join(chunks), original) | |
129 |
|
148 | |||
130 | # Similar to above except we have a constant read() size. |
|
149 | # Similar to above except we have a constant read() size. | |
131 | @hypothesis.settings( |
|
150 | @hypothesis.settings( | |
132 |
suppress_health_check=[hypothesis.HealthCheck.large_base_example] |
|
151 | suppress_health_check=[hypothesis.HealthCheck.large_base_example] | |
133 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
152 | ) | |
134 | level=strategies.integers(min_value=1, max_value=5), |
|
153 | @hypothesis.given( | |
135 | streaming=strategies.booleans(), |
|
154 | original=strategies.sampled_from(random_input_data()), | |
136 | source_read_size=strategies.integers(1, 1048576), |
|
155 | level=strategies.integers(min_value=1, max_value=5), | |
137 | read_size=strategies.integers(-1, 131072)) |
|
156 | streaming=strategies.booleans(), | |
138 | def test_buffer_source_constant_read_size(self, original, level, streaming, |
|
157 | source_read_size=strategies.integers(1, 1048576), | |
139 | source_read_size, read_size): |
|
158 | read_size=strategies.integers(-1, 131072), | |
|
159 | ) | |||
|
160 | def test_buffer_source_constant_read_size( | |||
|
161 | self, original, level, streaming, source_read_size, read_size | |||
|
162 | ): | |||
140 | if read_size == 0: |
|
163 | if read_size == 0: | |
141 | read_size = -1 |
|
164 | read_size = -1 | |
142 |
|
165 | |||
@@ -162,16 +185,18 b' class TestDecompressor_stream_reader_fuz' | |||||
162 |
|
185 | |||
163 | chunks.append(chunk) |
|
186 | chunks.append(chunk) | |
164 |
|
187 | |||
165 |
self.assertEqual(b |
|
188 | self.assertEqual(b"".join(chunks), original) | |
166 |
|
189 | |||
167 | @hypothesis.settings( |
|
190 | @hypothesis.settings( | |
168 |
suppress_health_check=[hypothesis.HealthCheck.large_base_example] |
|
191 | suppress_health_check=[hypothesis.HealthCheck.large_base_example] | |
169 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
192 | ) | |
170 | level=strategies.integers(min_value=1, max_value=5), |
|
193 | @hypothesis.given( | |
171 | streaming=strategies.booleans(), |
|
194 | original=strategies.sampled_from(random_input_data()), | |
172 | source_read_size=strategies.integers(1, 1048576)) |
|
195 | level=strategies.integers(min_value=1, max_value=5), | |
173 | def test_stream_source_readall(self, original, level, streaming, |
|
196 | streaming=strategies.booleans(), | |
174 | source_read_size): |
|
197 | source_read_size=strategies.integers(1, 1048576), | |
|
198 | ) | |||
|
199 | def test_stream_source_readall(self, original, level, streaming, source_read_size): | |||
175 | cctx = zstd.ZstdCompressor(level=level) |
|
200 | cctx = zstd.ZstdCompressor(level=level) | |
176 |
|
201 | |||
177 | if streaming: |
|
202 | if streaming: | |
@@ -190,14 +215,21 b' class TestDecompressor_stream_reader_fuz' | |||||
190 | self.assertEqual(data, original) |
|
215 | self.assertEqual(data, original) | |
191 |
|
216 | |||
192 | @hypothesis.settings( |
|
217 | @hypothesis.settings( | |
193 | suppress_health_check=[hypothesis.HealthCheck.large_base_example]) |
|
218 | suppress_health_check=[ | |
194 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
219 | hypothesis.HealthCheck.large_base_example, | |
195 | level=strategies.integers(min_value=1, max_value=5), |
|
220 | hypothesis.HealthCheck.too_slow, | |
196 | streaming=strategies.booleans(), |
|
221 | ] | |
197 | source_read_size=strategies.integers(1, 1048576), |
|
222 | ) | |
198 | read_sizes=strategies.data()) |
|
223 | @hypothesis.given( | |
199 | def test_stream_source_read1_variance(self, original, level, streaming, |
|
224 | original=strategies.sampled_from(random_input_data()), | |
200 | source_read_size, read_sizes): |
|
225 | level=strategies.integers(min_value=1, max_value=5), | |
|
226 | streaming=strategies.booleans(), | |||
|
227 | source_read_size=strategies.integers(1, 1048576), | |||
|
228 | read_sizes=strategies.data(), | |||
|
229 | ) | |||
|
230 | def test_stream_source_read1_variance( | |||
|
231 | self, original, level, streaming, source_read_size, read_sizes | |||
|
232 | ): | |||
201 | cctx = zstd.ZstdCompressor(level=level) |
|
233 | cctx = zstd.ZstdCompressor(level=level) | |
202 |
|
234 | |||
203 | if streaming: |
|
235 | if streaming: | |
@@ -222,17 +254,24 b' class TestDecompressor_stream_reader_fuz' | |||||
222 |
|
254 | |||
223 | chunks.append(chunk) |
|
255 | chunks.append(chunk) | |
224 |
|
256 | |||
225 |
self.assertEqual(b |
|
257 | self.assertEqual(b"".join(chunks), original) | |
226 |
|
258 | |||
227 | @hypothesis.settings( |
|
259 | @hypothesis.settings( | |
228 | suppress_health_check=[hypothesis.HealthCheck.large_base_example]) |
|
260 | suppress_health_check=[ | |
229 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
261 | hypothesis.HealthCheck.large_base_example, | |
230 | level=strategies.integers(min_value=1, max_value=5), |
|
262 | hypothesis.HealthCheck.too_slow, | |
231 | streaming=strategies.booleans(), |
|
263 | ] | |
232 | source_read_size=strategies.integers(1, 1048576), |
|
264 | ) | |
233 | read_sizes=strategies.data()) |
|
265 | @hypothesis.given( | |
234 | def test_stream_source_readinto1_variance(self, original, level, streaming, |
|
266 | original=strategies.sampled_from(random_input_data()), | |
235 | source_read_size, read_sizes): |
|
267 | level=strategies.integers(min_value=1, max_value=5), | |
|
268 | streaming=strategies.booleans(), | |||
|
269 | source_read_size=strategies.integers(1, 1048576), | |||
|
270 | read_sizes=strategies.data(), | |||
|
271 | ) | |||
|
272 | def test_stream_source_readinto1_variance( | |||
|
273 | self, original, level, streaming, source_read_size, read_sizes | |||
|
274 | ): | |||
236 | cctx = zstd.ZstdCompressor(level=level) |
|
275 | cctx = zstd.ZstdCompressor(level=level) | |
237 |
|
276 | |||
238 | if streaming: |
|
277 | if streaming: | |
@@ -259,18 +298,24 b' class TestDecompressor_stream_reader_fuz' | |||||
259 |
|
298 | |||
260 | chunks.append(bytes(b[0:count])) |
|
299 | chunks.append(bytes(b[0:count])) | |
261 |
|
300 | |||
262 |
self.assertEqual(b |
|
301 | self.assertEqual(b"".join(chunks), original) | |
263 |
|
302 | |||
264 | @hypothesis.settings( |
|
303 | @hypothesis.settings( | |
265 | suppress_health_check=[hypothesis.HealthCheck.large_base_example]) |
|
304 | suppress_health_check=[ | |
|
305 | hypothesis.HealthCheck.large_base_example, | |||
|
306 | hypothesis.HealthCheck.too_slow, | |||
|
307 | ] | |||
|
308 | ) | |||
266 | @hypothesis.given( |
|
309 | @hypothesis.given( | |
267 | original=strategies.sampled_from(random_input_data()), |
|
310 | original=strategies.sampled_from(random_input_data()), | |
268 | level=strategies.integers(min_value=1, max_value=5), |
|
311 | level=strategies.integers(min_value=1, max_value=5), | |
269 | source_read_size=strategies.integers(1, 1048576), |
|
312 | source_read_size=strategies.integers(1, 1048576), | |
270 | seek_amounts=strategies.data(), |
|
313 | seek_amounts=strategies.data(), | |
271 |
read_sizes=strategies.data() |
|
314 | read_sizes=strategies.data(), | |
272 | def test_relative_seeks(self, original, level, source_read_size, seek_amounts, |
|
315 | ) | |
273 | read_sizes): |
|
316 | def test_relative_seeks( | |
|
317 | self, original, level, source_read_size, seek_amounts, read_sizes | |||
|
318 | ): | |||
274 | cctx = zstd.ZstdCompressor(level=level) |
|
319 | cctx = zstd.ZstdCompressor(level=level) | |
275 | frame = cctx.compress(original) |
|
320 | frame = cctx.compress(original) | |
276 |
|
321 | |||
@@ -288,18 +333,24 b' class TestDecompressor_stream_reader_fuz' | |||||
288 | if not chunk: |
|
333 | if not chunk: | |
289 | break |
|
334 | break | |
290 |
|
335 | |||
291 | self.assertEqual(original[offset:offset + len(chunk)], chunk) |
|
336 | self.assertEqual(original[offset : offset + len(chunk)], chunk) | |
292 |
|
337 | |||
293 | @hypothesis.settings( |
|
338 | @hypothesis.settings( | |
294 | suppress_health_check=[hypothesis.HealthCheck.large_base_example]) |
|
339 | suppress_health_check=[ | |
|
340 | hypothesis.HealthCheck.large_base_example, | |||
|
341 | hypothesis.HealthCheck.too_slow, | |||
|
342 | ] | |||
|
343 | ) | |||
295 | @hypothesis.given( |
|
344 | @hypothesis.given( | |
296 | originals=strategies.data(), |
|
345 | originals=strategies.data(), | |
297 | frame_count=strategies.integers(min_value=2, max_value=10), |
|
346 | frame_count=strategies.integers(min_value=2, max_value=10), | |
298 | level=strategies.integers(min_value=1, max_value=5), |
|
347 | level=strategies.integers(min_value=1, max_value=5), | |
299 | source_read_size=strategies.integers(1, 1048576), |
|
348 | source_read_size=strategies.integers(1, 1048576), | |
300 |
read_sizes=strategies.data() |
|
349 | read_sizes=strategies.data(), | |
301 | def test_multiple_frames(self, originals, frame_count, level, |
|
350 | ) | |
302 | source_read_size, read_sizes): |
|
351 | def test_multiple_frames( | |
|
352 | self, originals, frame_count, level, source_read_size, read_sizes | |||
|
353 | ): | |||
303 |
|
354 | |||
304 | cctx = zstd.ZstdCompressor(level=level) |
|
355 | cctx = zstd.ZstdCompressor(level=level) | |
305 | source = io.BytesIO() |
|
356 | source = io.BytesIO() | |
@@ -314,8 +365,9 b' class TestDecompressor_stream_reader_fuz' | |||||
314 |
|
365 | |||
315 | dctx = zstd.ZstdDecompressor() |
|
366 | dctx = zstd.ZstdDecompressor() | |
316 | buffer.seek(0) |
|
367 | buffer.seek(0) | |
317 |
reader = dctx.stream_reader( |
|
368 | reader = dctx.stream_reader( | |
318 | read_across_frames=True) |
|
369 | buffer, read_size=source_read_size, read_across_frames=True | |
|
370 | ) | |||
319 |
|
371 | |||
320 | chunks = [] |
|
372 | chunks = [] | |
321 |
|
373 | |||
@@ -328,16 +380,24 b' class TestDecompressor_stream_reader_fuz' | |||||
328 |
|
380 | |||
329 | chunks.append(chunk) |
|
381 | chunks.append(chunk) | |
330 |
|
382 | |||
331 |
self.assertEqual(source.getvalue(), b |
|
383 | self.assertEqual(source.getvalue(), b"".join(chunks)) | |
332 |
|
384 | |||
333 |
|
385 | |||
334 |
@unittest.skipUnless( |
|
386 | @unittest.skipUnless("ZSTD_SLOW_TESTS" in os.environ, "ZSTD_SLOW_TESTS not set") | |
335 | @make_cffi |
|
387 | @make_cffi | |
336 |
class TestDecompressor_stream_writer_fuzzing( |
|
388 | class TestDecompressor_stream_writer_fuzzing(TestCase): | |
337 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
389 | @hypothesis.settings( | |
338 | level=strategies.integers(min_value=1, max_value=5), |
|
390 | suppress_health_check=[ | |
339 | write_size=strategies.integers(min_value=1, max_value=8192), |
|
391 | hypothesis.HealthCheck.large_base_example, | |
340 | input_sizes=strategies.data()) |
|
392 | hypothesis.HealthCheck.too_slow, | |
|
393 | ] | |||
|
394 | ) | |||
|
395 | @hypothesis.given( | |||
|
396 | original=strategies.sampled_from(random_input_data()), | |||
|
397 | level=strategies.integers(min_value=1, max_value=5), | |||
|
398 | write_size=strategies.integers(min_value=1, max_value=8192), | |||
|
399 | input_sizes=strategies.data(), | |||
|
400 | ) | |||
341 | def test_write_size_variance(self, original, level, write_size, input_sizes): |
|
401 | def test_write_size_variance(self, original, level, write_size, input_sizes): | |
342 | cctx = zstd.ZstdCompressor(level=level) |
|
402 | cctx = zstd.ZstdCompressor(level=level) | |
343 | frame = cctx.compress(original) |
|
403 | frame = cctx.compress(original) | |
@@ -358,13 +418,21 b' class TestDecompressor_stream_writer_fuz' | |||||
358 | self.assertEqual(dest.getvalue(), original) |
|
418 | self.assertEqual(dest.getvalue(), original) | |
359 |
|
419 | |||
360 |
|
420 | |||
361 |
@unittest.skipUnless( |
|
421 | @unittest.skipUnless("ZSTD_SLOW_TESTS" in os.environ, "ZSTD_SLOW_TESTS not set") | |
362 | @make_cffi |
|
422 | @make_cffi | |
363 |
class TestDecompressor_copy_stream_fuzzing( |
|
423 | class TestDecompressor_copy_stream_fuzzing(TestCase): | |
364 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
424 | @hypothesis.settings( | |
365 | level=strategies.integers(min_value=1, max_value=5), |
|
425 | suppress_health_check=[ | |
366 | read_size=strategies.integers(min_value=1, max_value=8192), |
|
426 | hypothesis.HealthCheck.large_base_example, | |
367 | write_size=strategies.integers(min_value=1, max_value=8192)) |
|
427 | hypothesis.HealthCheck.too_slow, | |
|
428 | ] | |||
|
429 | ) | |||
|
430 | @hypothesis.given( | |||
|
431 | original=strategies.sampled_from(random_input_data()), | |||
|
432 | level=strategies.integers(min_value=1, max_value=5), | |||
|
433 | read_size=strategies.integers(min_value=1, max_value=8192), | |||
|
434 | write_size=strategies.integers(min_value=1, max_value=8192), | |||
|
435 | ) | |||
368 | def test_read_write_size_variance(self, original, level, read_size, write_size): |
|
436 | def test_read_write_size_variance(self, original, level, read_size, write_size): | |
369 | cctx = zstd.ZstdCompressor(level=level) |
|
437 | cctx = zstd.ZstdCompressor(level=level) | |
370 | frame = cctx.compress(original) |
|
438 | frame = cctx.compress(original) | |
@@ -378,12 +446,20 b' class TestDecompressor_copy_stream_fuzzi' | |||||
378 | self.assertEqual(dest.getvalue(), original) |
|
446 | self.assertEqual(dest.getvalue(), original) | |
379 |
|
447 | |||
380 |
|
448 | |||
381 |
@unittest.skipUnless( |
|
449 | @unittest.skipUnless("ZSTD_SLOW_TESTS" in os.environ, "ZSTD_SLOW_TESTS not set") | |
382 | @make_cffi |
|
450 | @make_cffi | |
383 |
class TestDecompressor_decompressobj_fuzzing( |
|
451 | class TestDecompressor_decompressobj_fuzzing(TestCase): | |
384 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
452 | @hypothesis.settings( | |
385 | level=strategies.integers(min_value=1, max_value=5), |
|
453 | suppress_health_check=[ | |
386 | chunk_sizes=strategies.data()) |
|
454 | hypothesis.HealthCheck.large_base_example, | |
|
455 | hypothesis.HealthCheck.too_slow, | |||
|
456 | ] | |||
|
457 | ) | |||
|
458 | @hypothesis.given( | |||
|
459 | original=strategies.sampled_from(random_input_data()), | |||
|
460 | level=strategies.integers(min_value=1, max_value=5), | |||
|
461 | chunk_sizes=strategies.data(), | |||
|
462 | ) | |||
387 | def test_random_input_sizes(self, original, level, chunk_sizes): |
|
463 | def test_random_input_sizes(self, original, level, chunk_sizes): | |
388 | cctx = zstd.ZstdCompressor(level=level) |
|
464 | cctx = zstd.ZstdCompressor(level=level) | |
389 | frame = cctx.compress(original) |
|
465 | frame = cctx.compress(original) | |
@@ -402,13 +478,22 b' class TestDecompressor_decompressobj_fuz' | |||||
402 |
|
478 | |||
403 | chunks.append(dobj.decompress(chunk)) |
|
479 | chunks.append(dobj.decompress(chunk)) | |
404 |
|
480 | |||
405 |
self.assertEqual(b |
|
481 | self.assertEqual(b"".join(chunks), original) | |
406 |
|
482 | |||
407 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
483 | @hypothesis.settings( | |
408 | level=strategies.integers(min_value=1, max_value=5), |
|
484 | suppress_health_check=[ | |
409 | write_size=strategies.integers(min_value=1, |
|
485 | hypothesis.HealthCheck.large_base_example, | |
410 | max_value=4 * zstd.DECOMPRESSION_RECOMMENDED_OUTPUT_SIZE), |
|
486 | hypothesis.HealthCheck.too_slow, | |
411 | chunk_sizes=strategies.data()) |
|
487 | ] | |
|
488 | ) | |||
|
489 | @hypothesis.given( | |||
|
490 | original=strategies.sampled_from(random_input_data()), | |||
|
491 | level=strategies.integers(min_value=1, max_value=5), | |||
|
492 | write_size=strategies.integers( | |||
|
493 | min_value=1, max_value=4 * zstd.DECOMPRESSION_RECOMMENDED_OUTPUT_SIZE | |||
|
494 | ), | |||
|
495 | chunk_sizes=strategies.data(), | |||
|
496 | ) | |||
412 | def test_random_output_sizes(self, original, level, write_size, chunk_sizes): |
|
497 | def test_random_output_sizes(self, original, level, write_size, chunk_sizes): | |
413 | cctx = zstd.ZstdCompressor(level=level) |
|
498 | cctx = zstd.ZstdCompressor(level=level) | |
414 | frame = cctx.compress(original) |
|
499 | frame = cctx.compress(original) | |
@@ -427,16 +512,18 b' class TestDecompressor_decompressobj_fuz' | |||||
427 |
|
512 | |||
428 | chunks.append(dobj.decompress(chunk)) |
|
513 | chunks.append(dobj.decompress(chunk)) | |
429 |
|
514 | |||
430 |
self.assertEqual(b |
|
515 | self.assertEqual(b"".join(chunks), original) | |
431 |
|
516 | |||
432 |
|
517 | |||
433 |
@unittest.skipUnless( |
|
518 | @unittest.skipUnless("ZSTD_SLOW_TESTS" in os.environ, "ZSTD_SLOW_TESTS not set") | |
434 | @make_cffi |
|
519 | @make_cffi | |
435 |
class TestDecompressor_read_to_iter_fuzzing( |
|
520 | class TestDecompressor_read_to_iter_fuzzing(TestCase): | |
436 | @hypothesis.given(original=strategies.sampled_from(random_input_data()), |
|
521 | @hypothesis.given( | |
437 | level=strategies.integers(min_value=1, max_value=5), |
|
522 | original=strategies.sampled_from(random_input_data()), | |
438 |
|
|
523 | level=strategies.integers(min_value=1, max_value=5), | |
439 |
|
|
524 | read_size=strategies.integers(min_value=1, max_value=4096), | |
|
525 | write_size=strategies.integers(min_value=1, max_value=4096), | |||
|
526 | ) | |||
440 | def test_read_write_size_variance(self, original, level, read_size, write_size): |
|
527 | def test_read_write_size_variance(self, original, level, read_size, write_size): | |
441 | cctx = zstd.ZstdCompressor(level=level) |
|
528 | cctx = zstd.ZstdCompressor(level=level) | |
442 | frame = cctx.compress(original) |
|
529 | frame = cctx.compress(original) | |
@@ -444,29 +531,33 b' class TestDecompressor_read_to_iter_fuzz' | |||||
444 | source = io.BytesIO(frame) |
|
531 | source = io.BytesIO(frame) | |
445 |
|
532 | |||
446 | dctx = zstd.ZstdDecompressor() |
|
533 | dctx = zstd.ZstdDecompressor() | |
447 | chunks = list(dctx.read_to_iter(source, read_size=read_size, write_size=write_size)) |
|
534 | chunks = list( | |
|
535 | dctx.read_to_iter(source, read_size=read_size, write_size=write_size) | |||
|
536 | ) | |||
448 |
|
537 | |||
449 |
self.assertEqual(b |
|
538 | self.assertEqual(b"".join(chunks), original) | |
450 |
|
539 | |||
451 |
|
540 | |||
452 |
@unittest.skipUnless( |
|
541 | @unittest.skipUnless("ZSTD_SLOW_TESTS" in os.environ, "ZSTD_SLOW_TESTS not set") | |
453 |
class TestDecompressor_multi_decompress_to_buffer_fuzzing( |
|
542 | class TestDecompressor_multi_decompress_to_buffer_fuzzing(TestCase): | |
454 | @hypothesis.given(original=strategies.lists(strategies.sampled_from(random_input_data()), |
|
543 | @hypothesis.given( | |
455 | min_size=1, max_size=1024), |
|
544 | original=strategies.lists( | |
456 | threads=strategies.integers(min_value=1, max_value=8), |
|
545 | strategies.sampled_from(random_input_data()), min_size=1, max_size=1024 | |
457 | use_dict=strategies.booleans()) |
|
546 | ), | |
|
547 | threads=strategies.integers(min_value=1, max_value=8), | |||
|
548 | use_dict=strategies.booleans(), | |||
|
549 | ) | |||
458 | def test_data_equivalence(self, original, threads, use_dict): |
|
550 | def test_data_equivalence(self, original, threads, use_dict): | |
459 | kwargs = {} |
|
551 | kwargs = {} | |
460 | if use_dict: |
|
552 | if use_dict: | |
461 |
kwargs[ |
|
553 | kwargs["dict_data"] = zstd.ZstdCompressionDict(original[0]) | |
462 |
|
554 | |||
463 |
cctx = zstd.ZstdCompressor( |
|
555 | cctx = zstd.ZstdCompressor( | |
464 | write_content_size=True, |
|
556 | level=1, write_content_size=True, write_checksum=True, **kwargs | |
465 | write_checksum=True, |
|
557 | ) | |
466 | **kwargs) |
|
|||
467 |
|
558 | |||
468 |
if not hasattr(cctx, |
|
559 | if not hasattr(cctx, "multi_compress_to_buffer"): | |
469 |
self.skipTest( |
|
560 | self.skipTest("multi_compress_to_buffer not available") | |
470 |
|
561 | |||
471 | frames_buffer = cctx.multi_compress_to_buffer(original, threads=-1) |
|
562 | frames_buffer = cctx.multi_compress_to_buffer(original, threads=-1) | |
472 |
|
563 |
@@ -2,14 +2,14 b' import unittest' | |||||
2 |
|
2 | |||
3 | import zstandard as zstd |
|
3 | import zstandard as zstd | |
4 |
|
4 | |||
5 |
from . |
|
5 | from .common import ( | |
6 | make_cffi, |
|
6 | make_cffi, | |
|
7 | TestCase, | |||
7 | ) |
|
8 | ) | |
8 |
|
9 | |||
9 |
|
10 | |||
10 | @make_cffi |
|
11 | @make_cffi | |
11 |
class TestSizes( |
|
12 | class TestSizes(TestCase): | |
12 | def test_decompression_size(self): |
|
13 | def test_decompression_size(self): | |
13 | size = zstd.estimate_decompression_context_size() |
|
14 | size = zstd.estimate_decompression_context_size() | |
14 | self.assertGreater(size, 100000) |
|
15 | self.assertGreater(size, 100000) | |
15 |
|
@@ -4,65 +4,66 b' import unittest' | |||||
4 |
|
4 | |||
5 | import zstandard as zstd |
|
5 | import zstandard as zstd | |
6 |
|
6 | |||
7 |
from . |
|
7 | from .common import ( | |
8 | make_cffi, |
|
8 | make_cffi, | |
|
9 | TestCase, | |||
9 | ) |
|
10 | ) | |
10 |
|
11 | |||
11 |
|
12 | |||
12 | @make_cffi |
|
13 | @make_cffi | |
13 |
class TestModuleAttributes( |
|
14 | class TestModuleAttributes(TestCase): | |
14 | def test_version(self): |
|
15 | def test_version(self): | |
15 |
self.assertEqual(zstd.ZSTD_VERSION, (1, 4, |
|
16 | self.assertEqual(zstd.ZSTD_VERSION, (1, 4, 4)) | |
16 |
|
17 | |||
17 |
self.assertEqual(zstd.__version__, |
|
18 | self.assertEqual(zstd.__version__, "0.13.0") | |
18 |
|
19 | |||
19 | def test_constants(self): |
|
20 | def test_constants(self): | |
20 | self.assertEqual(zstd.MAX_COMPRESSION_LEVEL, 22) |
|
21 | self.assertEqual(zstd.MAX_COMPRESSION_LEVEL, 22) | |
21 |
self.assertEqual(zstd.FRAME_HEADER, b |
|
22 | self.assertEqual(zstd.FRAME_HEADER, b"\x28\xb5\x2f\xfd") | |
22 |
|
23 | |||
23 | def test_hasattr(self): |
|
24 | def test_hasattr(self): | |
24 | attrs = ( |
|
25 | attrs = ( | |
25 |
|
|
26 | "CONTENTSIZE_UNKNOWN", | |
26 |
|
|
27 | "CONTENTSIZE_ERROR", | |
27 |
|
|
28 | "COMPRESSION_RECOMMENDED_INPUT_SIZE", | |
28 |
|
|
29 | "COMPRESSION_RECOMMENDED_OUTPUT_SIZE", | |
29 |
|
|
30 | "DECOMPRESSION_RECOMMENDED_INPUT_SIZE", | |
30 |
|
|
31 | "DECOMPRESSION_RECOMMENDED_OUTPUT_SIZE", | |
31 |
|
|
32 | "MAGIC_NUMBER", | |
32 |
|
|
33 | "FLUSH_BLOCK", | |
33 |
|
|
34 | "FLUSH_FRAME", | |
34 |
|
|
35 | "BLOCKSIZELOG_MAX", | |
35 |
|
|
36 | "BLOCKSIZE_MAX", | |
36 |
|
|
37 | "WINDOWLOG_MIN", | |
37 |
|
|
38 | "WINDOWLOG_MAX", | |
38 |
|
|
39 | "CHAINLOG_MIN", | |
39 |
|
|
40 | "CHAINLOG_MAX", | |
40 |
|
|
41 | "HASHLOG_MIN", | |
41 |
|
|
42 | "HASHLOG_MAX", | |
42 |
|
|
43 | "HASHLOG3_MAX", | |
43 |
|
|
44 | "MINMATCH_MIN", | |
44 |
|
|
45 | "MINMATCH_MAX", | |
45 |
|
|
46 | "SEARCHLOG_MIN", | |
46 |
|
|
47 | "SEARCHLOG_MAX", | |
47 |
|
|
48 | "SEARCHLENGTH_MIN", | |
48 |
|
|
49 | "SEARCHLENGTH_MAX", | |
49 |
|
|
50 | "TARGETLENGTH_MIN", | |
50 |
|
|
51 | "TARGETLENGTH_MAX", | |
51 |
|
|
52 | "LDM_MINMATCH_MIN", | |
52 |
|
|
53 | "LDM_MINMATCH_MAX", | |
53 |
|
|
54 | "LDM_BUCKETSIZELOG_MAX", | |
54 |
|
|
55 | "STRATEGY_FAST", | |
55 |
|
|
56 | "STRATEGY_DFAST", | |
56 |
|
|
57 | "STRATEGY_GREEDY", | |
57 |
|
|
58 | "STRATEGY_LAZY", | |
58 |
|
|
59 | "STRATEGY_LAZY2", | |
59 |
|
|
60 | "STRATEGY_BTLAZY2", | |
60 |
|
|
61 | "STRATEGY_BTOPT", | |
61 |
|
|
62 | "STRATEGY_BTULTRA", | |
62 |
|
|
63 | "STRATEGY_BTULTRA2", | |
63 |
|
|
64 | "DICT_TYPE_AUTO", | |
64 |
|
|
65 | "DICT_TYPE_RAWCONTENT", | |
65 |
|
|
66 | "DICT_TYPE_FULLDICT", | |
66 | ) |
|
67 | ) | |
67 |
|
68 | |||
68 | for a in attrs: |
|
69 | for a in attrs: |
@@ -4,10 +4,11 b' import unittest' | |||||
4 |
|
4 | |||
5 | import zstandard as zstd |
|
5 | import zstandard as zstd | |
6 |
|
6 | |||
7 |
from . |
|
7 | from .common import ( | |
8 | generate_samples, |
|
8 | generate_samples, | |
9 | make_cffi, |
|
9 | make_cffi, | |
10 | random_input_data, |
|
10 | random_input_data, | |
|
11 | TestCase, | |||
11 | ) |
|
12 | ) | |
12 |
|
13 | |||
13 | if sys.version_info[0] >= 3: |
|
14 | if sys.version_info[0] >= 3: | |
@@ -17,24 +18,24 b' else:' | |||||
17 |
|
18 | |||
18 |
|
19 | |||
19 | @make_cffi |
|
20 | @make_cffi | |
20 |
class TestTrainDictionary( |
|
21 | class TestTrainDictionary(TestCase): | |
21 | def test_no_args(self): |
|
22 | def test_no_args(self): | |
22 | with self.assertRaises(TypeError): |
|
23 | with self.assertRaises(TypeError): | |
23 | zstd.train_dictionary() |
|
24 | zstd.train_dictionary() | |
24 |
|
25 | |||
25 | def test_bad_args(self): |
|
26 | def test_bad_args(self): | |
26 | with self.assertRaises(TypeError): |
|
27 | with self.assertRaises(TypeError): | |
27 |
zstd.train_dictionary(8192, u |
|
28 | zstd.train_dictionary(8192, u"foo") | |
28 |
|
29 | |||
29 | with self.assertRaises(ValueError): |
|
30 | with self.assertRaises(ValueError): | |
30 |
zstd.train_dictionary(8192, [u |
|
31 | zstd.train_dictionary(8192, [u"foo"]) | |
31 |
|
32 | |||
32 | def test_no_params(self): |
|
33 | def test_no_params(self): | |
33 | d = zstd.train_dictionary(8192, random_input_data()) |
|
34 | d = zstd.train_dictionary(8192, random_input_data()) | |
34 | self.assertIsInstance(d.dict_id(), int_type) |
|
35 | self.assertIsInstance(d.dict_id(), int_type) | |
35 |
|
36 | |||
36 | # The dictionary ID may be different across platforms. |
|
37 | # The dictionary ID may be different across platforms. | |
37 |
expected = b |
|
38 | expected = b"\x37\xa4\x30\xec" + struct.pack("<I", d.dict_id()) | |
38 |
|
39 | |||
39 | data = d.as_bytes() |
|
40 | data = d.as_bytes() | |
40 | self.assertEqual(data[0:8], expected) |
|
41 | self.assertEqual(data[0:8], expected) | |
@@ -44,46 +45,48 b' class TestTrainDictionary(unittest.TestC' | |||||
44 | self.assertIsInstance(d.dict_id(), int_type) |
|
45 | self.assertIsInstance(d.dict_id(), int_type) | |
45 |
|
46 | |||
46 | data = d.as_bytes() |
|
47 | data = d.as_bytes() | |
47 |
self.assertEqual(data[0:4], b |
|
48 | self.assertEqual(data[0:4], b"\x37\xa4\x30\xec") | |
48 |
|
49 | |||
49 | self.assertEqual(d.k, 64) |
|
50 | self.assertEqual(d.k, 64) | |
50 | self.assertEqual(d.d, 16) |
|
51 | self.assertEqual(d.d, 16) | |
51 |
|
52 | |||
52 | def test_set_dict_id(self): |
|
53 | def test_set_dict_id(self): | |
53 | d = zstd.train_dictionary(8192, generate_samples(), k=64, d=16, |
|
54 | d = zstd.train_dictionary(8192, generate_samples(), k=64, d=16, dict_id=42) | |
54 | dict_id=42) |
|
|||
55 | self.assertEqual(d.dict_id(), 42) |
|
55 | self.assertEqual(d.dict_id(), 42) | |
56 |
|
56 | |||
57 | def test_optimize(self): |
|
57 | def test_optimize(self): | |
58 | d = zstd.train_dictionary(8192, generate_samples(), threads=-1, steps=1, |
|
58 | d = zstd.train_dictionary(8192, generate_samples(), threads=-1, steps=1, d=16) | |
59 | d=16) |
|
|||
60 |
|
59 | |||
61 | # This varies by platform. |
|
60 | # This varies by platform. | |
62 | self.assertIn(d.k, (50, 2000)) |
|
61 | self.assertIn(d.k, (50, 2000)) | |
63 | self.assertEqual(d.d, 16) |
|
62 | self.assertEqual(d.d, 16) | |
64 |
|
63 | |||
|
64 | ||||
65 | @make_cffi |
|
65 | @make_cffi | |
66 |
class TestCompressionDict( |
|
66 | class TestCompressionDict(TestCase): | |
67 | def test_bad_mode(self): |
|
67 | def test_bad_mode(self): | |
68 |
with self.assertRaisesRegex |
|
68 | with self.assertRaisesRegex(ValueError, "invalid dictionary load mode"): | |
69 |
zstd.ZstdCompressionDict(b |
|
69 | zstd.ZstdCompressionDict(b"foo", dict_type=42) | |
70 |
|
70 | |||
71 | def test_bad_precompute_compress(self): |
|
71 | def test_bad_precompute_compress(self): | |
72 | d = zstd.train_dictionary(8192, generate_samples(), k=64, d=16) |
|
72 | d = zstd.train_dictionary(8192, generate_samples(), k=64, d=16) | |
73 |
|
73 | |||
74 |
with self.assertRaisesRegex |
|
74 | with self.assertRaisesRegex(ValueError, "must specify one of level or "): | |
75 | d.precompute_compress() |
|
75 | d.precompute_compress() | |
76 |
|
76 | |||
77 |
with self.assertRaisesRegex |
|
77 | with self.assertRaisesRegex(ValueError, "must only specify one of level or "): | |
78 |
d.precompute_compress( |
|
78 | d.precompute_compress( | |
79 |
|
|
79 | level=3, compression_params=zstd.CompressionParameters() | |
|
80 | ) | |||
80 |
|
81 | |||
81 | def test_precompute_compress_rawcontent(self): |
|
82 | def test_precompute_compress_rawcontent(self): | |
82 |
d = zstd.ZstdCompressionDict( |
|
83 | d = zstd.ZstdCompressionDict( | |
83 |
|
|
84 | b"dictcontent" * 64, dict_type=zstd.DICT_TYPE_RAWCONTENT | |
|
85 | ) | |||
84 | d.precompute_compress(level=1) |
|
86 | d.precompute_compress(level=1) | |
85 |
|
87 | |||
86 |
d = zstd.ZstdCompressionDict( |
|
88 | d = zstd.ZstdCompressionDict( | |
87 |
|
|
89 | b"dictcontent" * 64, dict_type=zstd.DICT_TYPE_FULLDICT | |
88 | with self.assertRaisesRegexp(zstd.ZstdError, 'unable to precompute dictionary'): |
|
90 | ) | |
|
91 | with self.assertRaisesRegex(zstd.ZstdError, "unable to precompute dictionary"): | |||
89 | d.precompute_compress(level=1) |
|
92 | d.precompute_compress(level=1) |
@@ -28,38 +28,48 b' import platform' | |||||
28 | # defining a variable and `setup.py` could write the file with whatever |
|
28 | # defining a variable and `setup.py` could write the file with whatever | |
29 | # policy was specified at build time. Until someone needs it, we go with |
|
29 | # policy was specified at build time. Until someone needs it, we go with | |
30 | # the hacky but simple environment variable approach. |
|
30 | # the hacky but simple environment variable approach. | |
31 |
_module_policy = os.environ.get( |
|
31 | _module_policy = os.environ.get("PYTHON_ZSTANDARD_IMPORT_POLICY", "default") | |
32 |
|
32 | |||
33 |
if _module_policy == |
|
33 | if _module_policy == "default": | |
34 |
if platform.python_implementation() in ( |
|
34 | if platform.python_implementation() in ("CPython",): | |
35 | from zstd import * |
|
35 | from zstd import * | |
36 | backend = 'cext' |
|
36 | ||
37 | elif platform.python_implementation() in ('PyPy',): |
|
37 | backend = "cext" | |
|
38 | elif platform.python_implementation() in ("PyPy",): | |||
38 | from .cffi import * |
|
39 | from .cffi import * | |
39 | backend = 'cffi' |
|
40 | ||
|
41 | backend = "cffi" | |||
40 | else: |
|
42 | else: | |
41 | try: |
|
43 | try: | |
42 | from zstd import * |
|
44 | from zstd import * | |
43 | backend = 'cext' |
|
45 | ||
|
46 | backend = "cext" | |||
44 | except ImportError: |
|
47 | except ImportError: | |
45 | from .cffi import * |
|
48 | from .cffi import * | |
46 | backend = 'cffi' |
|
49 | ||
47 | elif _module_policy == 'cffi_fallback': |
|
50 | backend = "cffi" | |
|
51 | elif _module_policy == "cffi_fallback": | |||
48 | try: |
|
52 | try: | |
49 | from zstd import * |
|
53 | from zstd import * | |
50 | backend = 'cext' |
|
54 | ||
|
55 | backend = "cext" | |||
51 | except ImportError: |
|
56 | except ImportError: | |
52 | from .cffi import * |
|
57 | from .cffi import * | |
53 | backend = 'cffi' |
|
58 | ||
54 | elif _module_policy == 'cext': |
|
59 | backend = "cffi" | |
|
60 | elif _module_policy == "cext": | |||
55 | from zstd import * |
|
61 | from zstd import * | |
56 | backend = 'cext' |
|
62 | ||
57 | elif _module_policy == 'cffi': |
|
63 | backend = "cext" | |
|
64 | elif _module_policy == "cffi": | |||
58 | from .cffi import * |
|
65 | from .cffi import * | |
59 | backend = 'cffi' |
|
66 | ||
|
67 | backend = "cffi" | |||
60 | else: |
|
68 | else: | |
61 | raise ImportError('unknown module import policy: %s; use default, cffi_fallback, ' |
|
69 | raise ImportError( | |
62 | 'cext, or cffi' % _module_policy) |
|
70 | "unknown module import policy: %s; use default, cffi_fallback, " | |
|
71 | "cext, or cffi" % _module_policy | |||
|
72 | ) | |||
63 |
|
73 | |||
64 | # Keep this in sync with python-zstandard.h. |
|
74 | # Keep this in sync with python-zstandard.h. | |
65 |
__version__ = |
|
75 | __version__ = "0.13.0" |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from mercurial/default.d/mergetools.rc to mercurial/defaultrc/mergetools.rc |
|
NO CONTENT: file renamed from mercurial/default.d/mergetools.rc to mercurial/defaultrc/mergetools.rc |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from mercurial/help/bundlespec.txt to mercurial/helptext/bundlespec.txt |
|
NO CONTENT: file renamed from mercurial/help/bundlespec.txt to mercurial/helptext/bundlespec.txt |
1 | NO CONTENT: file renamed from mercurial/help/color.txt to mercurial/helptext/color.txt |
|
NO CONTENT: file renamed from mercurial/help/color.txt to mercurial/helptext/color.txt |
1 | NO CONTENT: file renamed from mercurial/help/common.txt to mercurial/helptext/common.txt |
|
NO CONTENT: file renamed from mercurial/help/common.txt to mercurial/helptext/common.txt |
1 | NO CONTENT: file renamed from mercurial/help/config.txt to mercurial/helptext/config.txt |
|
NO CONTENT: file renamed from mercurial/help/config.txt to mercurial/helptext/config.txt | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from mercurial/help/dates.txt to mercurial/helptext/dates.txt |
|
NO CONTENT: file renamed from mercurial/help/dates.txt to mercurial/helptext/dates.txt |
1 | NO CONTENT: file renamed from mercurial/help/deprecated.txt to mercurial/helptext/deprecated.txt |
|
NO CONTENT: file renamed from mercurial/help/deprecated.txt to mercurial/helptext/deprecated.txt |
1 | NO CONTENT: file renamed from mercurial/help/diffs.txt to mercurial/helptext/diffs.txt |
|
NO CONTENT: file renamed from mercurial/help/diffs.txt to mercurial/helptext/diffs.txt |
1 | NO CONTENT: file renamed from mercurial/help/environment.txt to mercurial/helptext/environment.txt |
|
NO CONTENT: file renamed from mercurial/help/environment.txt to mercurial/helptext/environment.txt | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from mercurial/help/extensions.txt to mercurial/helptext/extensions.txt |
|
NO CONTENT: file renamed from mercurial/help/extensions.txt to mercurial/helptext/extensions.txt |
1 | NO CONTENT: file renamed from mercurial/help/filesets.txt to mercurial/helptext/filesets.txt |
|
NO CONTENT: file renamed from mercurial/help/filesets.txt to mercurial/helptext/filesets.txt |
1 | NO CONTENT: file renamed from mercurial/help/flags.txt to mercurial/helptext/flags.txt |
|
NO CONTENT: file renamed from mercurial/help/flags.txt to mercurial/helptext/flags.txt |
1 | NO CONTENT: file renamed from mercurial/help/glossary.txt to mercurial/helptext/glossary.txt |
|
NO CONTENT: file renamed from mercurial/help/glossary.txt to mercurial/helptext/glossary.txt |
1 | NO CONTENT: file renamed from mercurial/help/hg-ssh.8.txt to mercurial/helptext/hg-ssh.8.txt |
|
NO CONTENT: file renamed from mercurial/help/hg-ssh.8.txt to mercurial/helptext/hg-ssh.8.txt |
1 | NO CONTENT: file renamed from mercurial/help/hg.1.txt to mercurial/helptext/hg.1.txt |
|
NO CONTENT: file renamed from mercurial/help/hg.1.txt to mercurial/helptext/hg.1.txt |
1 | NO CONTENT: file renamed from mercurial/help/hgignore.5.txt to mercurial/helptext/hgignore.5.txt |
|
NO CONTENT: file renamed from mercurial/help/hgignore.5.txt to mercurial/helptext/hgignore.5.txt |
1 | NO CONTENT: file renamed from mercurial/help/hgignore.txt to mercurial/helptext/hgignore.txt |
|
NO CONTENT: file renamed from mercurial/help/hgignore.txt to mercurial/helptext/hgignore.txt |
1 | NO CONTENT: file renamed from mercurial/help/hgrc.5.txt to mercurial/helptext/hgrc.5.txt |
|
NO CONTENT: file renamed from mercurial/help/hgrc.5.txt to mercurial/helptext/hgrc.5.txt |
1 | NO CONTENT: file renamed from mercurial/help/hgweb.txt to mercurial/helptext/hgweb.txt |
|
NO CONTENT: file renamed from mercurial/help/hgweb.txt to mercurial/helptext/hgweb.txt | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from mercurial/help/internals/bundle2.txt to mercurial/helptext/internals/bundle2.txt |
|
NO CONTENT: file renamed from mercurial/help/internals/bundle2.txt to mercurial/helptext/internals/bundle2.txt |
1 | NO CONTENT: file renamed from mercurial/help/internals/bundles.txt to mercurial/helptext/internals/bundles.txt |
|
NO CONTENT: file renamed from mercurial/help/internals/bundles.txt to mercurial/helptext/internals/bundles.txt |
1 | NO CONTENT: file renamed from mercurial/help/internals/cbor.txt to mercurial/helptext/internals/cbor.txt |
|
NO CONTENT: file renamed from mercurial/help/internals/cbor.txt to mercurial/helptext/internals/cbor.txt |
1 | NO CONTENT: file renamed from mercurial/help/internals/censor.txt to mercurial/helptext/internals/censor.txt |
|
NO CONTENT: file renamed from mercurial/help/internals/censor.txt to mercurial/helptext/internals/censor.txt |
1 | NO CONTENT: file renamed from mercurial/help/internals/changegroups.txt to mercurial/helptext/internals/changegroups.txt |
|
NO CONTENT: file renamed from mercurial/help/internals/changegroups.txt to mercurial/helptext/internals/changegroups.txt |
1 | NO CONTENT: file renamed from mercurial/help/internals/config.txt to mercurial/helptext/internals/config.txt |
|
NO CONTENT: file renamed from mercurial/help/internals/config.txt to mercurial/helptext/internals/config.txt |
1 | NO CONTENT: file renamed from mercurial/help/internals/extensions.txt to mercurial/helptext/internals/extensions.txt |
|
NO CONTENT: file renamed from mercurial/help/internals/extensions.txt to mercurial/helptext/internals/extensions.txt |
1 | NO CONTENT: file renamed from mercurial/help/internals/linelog.txt to mercurial/helptext/internals/linelog.txt |
|
NO CONTENT: file renamed from mercurial/help/internals/linelog.txt to mercurial/helptext/internals/linelog.txt |
1 | NO CONTENT: file renamed from mercurial/help/internals/mergestate.txt to mercurial/helptext/internals/mergestate.txt |
|
NO CONTENT: file renamed from mercurial/help/internals/mergestate.txt to mercurial/helptext/internals/mergestate.txt |
1 | NO CONTENT: file renamed from mercurial/help/internals/requirements.txt to mercurial/helptext/internals/requirements.txt |
|
NO CONTENT: file renamed from mercurial/help/internals/requirements.txt to mercurial/helptext/internals/requirements.txt |
1 | NO CONTENT: file renamed from mercurial/help/internals/revlogs.txt to mercurial/helptext/internals/revlogs.txt |
|
NO CONTENT: file renamed from mercurial/help/internals/revlogs.txt to mercurial/helptext/internals/revlogs.txt |
1 | NO CONTENT: file renamed from mercurial/help/internals/wireprotocol.txt to mercurial/helptext/internals/wireprotocol.txt |
|
NO CONTENT: file renamed from mercurial/help/internals/wireprotocol.txt to mercurial/helptext/internals/wireprotocol.txt |
1 | NO CONTENT: file renamed from mercurial/help/internals/wireprotocolrpc.txt to mercurial/helptext/internals/wireprotocolrpc.txt |
|
NO CONTENT: file renamed from mercurial/help/internals/wireprotocolrpc.txt to mercurial/helptext/internals/wireprotocolrpc.txt |
1 | NO CONTENT: file renamed from mercurial/help/internals/wireprotocolv2.txt to mercurial/helptext/internals/wireprotocolv2.txt |
|
NO CONTENT: file renamed from mercurial/help/internals/wireprotocolv2.txt to mercurial/helptext/internals/wireprotocolv2.txt |
1 | NO CONTENT: file renamed from mercurial/help/merge-tools.txt to mercurial/helptext/merge-tools.txt |
|
NO CONTENT: file renamed from mercurial/help/merge-tools.txt to mercurial/helptext/merge-tools.txt |
1 | NO CONTENT: file renamed from mercurial/help/pager.txt to mercurial/helptext/pager.txt |
|
NO CONTENT: file renamed from mercurial/help/pager.txt to mercurial/helptext/pager.txt |
1 | NO CONTENT: file renamed from mercurial/help/patterns.txt to mercurial/helptext/patterns.txt |
|
NO CONTENT: file renamed from mercurial/help/patterns.txt to mercurial/helptext/patterns.txt |
1 | NO CONTENT: file renamed from mercurial/help/phases.txt to mercurial/helptext/phases.txt |
|
NO CONTENT: file renamed from mercurial/help/phases.txt to mercurial/helptext/phases.txt |
1 | NO CONTENT: file renamed from mercurial/help/revisions.txt to mercurial/helptext/revisions.txt |
|
NO CONTENT: file renamed from mercurial/help/revisions.txt to mercurial/helptext/revisions.txt |
1 | NO CONTENT: file renamed from mercurial/help/scripting.txt to mercurial/helptext/scripting.txt |
|
NO CONTENT: file renamed from mercurial/help/scripting.txt to mercurial/helptext/scripting.txt | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from mercurial/help/subrepos.txt to mercurial/helptext/subrepos.txt |
|
NO CONTENT: file renamed from mercurial/help/subrepos.txt to mercurial/helptext/subrepos.txt |
1 | NO CONTENT: file renamed from mercurial/help/templates.txt to mercurial/helptext/templates.txt |
|
NO CONTENT: file renamed from mercurial/help/templates.txt to mercurial/helptext/templates.txt |
1 | NO CONTENT: file renamed from mercurial/help/urls.txt to mercurial/helptext/urls.txt |
|
NO CONTENT: file renamed from mercurial/help/urls.txt to mercurial/helptext/urls.txt |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file copied from mercurial/utils/procutil.py to mercurial/utils/resourceutil.py |
|
NO CONTENT: file copied from mercurial/utils/procutil.py to mercurial/utils/resourceutil.py | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file copied from rust/README.rst to rust/hgcli/README.rst |
|
NO CONTENT: file copied from rust/README.rst to rust/hgcli/README.rst | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file copied from tests/test-graft.t to tests/test-graft-interrupted.t |
|
NO CONTENT: file copied from tests/test-graft.t to tests/test-graft-interrupted.t | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file copied from tests/test-graft.t to tests/test-graft-rename.t |
|
NO CONTENT: file copied from tests/test-graft.t to tests/test-graft-rename.t | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now