lenc 1.2.0 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/lenc/encr.rb +1 -0
- data/lib/lenc/repo.rb +28 -13
- metadata +2 -3
- data/lib/lenc/_OLD_tools.rb +0 -628
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0599074c2a147d12b565284ba7d57126d1e4fda4
|
4
|
+
data.tar.gz: b78817f171113983d8c7a412191d4b78b1683045
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f19660e7bdde1ffb36153dd0947dbd9bfd66e3f05c71610a5ab4b5f9db931fd34ab57421c901bd77d54a7d5b9a80c6f53fcd71f24c46bc24a503dc56125ca911
|
7
|
+
data.tar.gz: d8c08ff48b5ea0deaf6d565e29d702e85b0a6625fb09fcbf1d578d3997f20f6dce0f619dc0e2f45c1942254da2ec1bd7b6d4ab6d47bfe59bb49264024917183f
|
data/lib/lenc/encr.rb
CHANGED
@@ -15,6 +15,7 @@ class EncrApp
|
|
15
15
|
opt :verbose,"verbose operation"
|
16
16
|
opt :where, "specify source directory (default = current directory)", :type => :strings
|
17
17
|
opt :quiet, "quiet operation"
|
18
|
+
opt :dryrun, "show which files will be modified, but make no changes"
|
18
19
|
end
|
19
20
|
|
20
21
|
options = Trollop::with_standard_exception_handling p do
|
data/lib/lenc/repo.rb
CHANGED
@@ -69,9 +69,13 @@ module LEnc
|
|
69
69
|
end
|
70
70
|
|
71
71
|
|
72
|
+
# We now ignore 'dot-underscore' files which OSX seems to create sometimes
|
73
|
+
# to store additional information about other files.
|
74
|
+
|
72
75
|
DEFAULTIGNORE = \
|
73
76
|
"#{LENC_REPO_FILENAME}\n " \
|
74
77
|
".DS_Store\n" + \
|
78
|
+
"._*\n" + \
|
75
79
|
".recoverdefaults\n"
|
76
80
|
|
77
81
|
STATE_CLOSED = 0
|
@@ -300,11 +304,13 @@ module LEnc
|
|
300
304
|
# @raise IllegalStateException if repository isn't open.
|
301
305
|
#
|
302
306
|
def perform_encrypt()
|
307
|
+
db = warndb 0
|
303
308
|
raise IllegalStateException if @state != STATE_OPEN
|
304
309
|
|
305
310
|
enc_dir = @encrDir
|
306
311
|
if in_place?
|
307
312
|
enc_dir = @repoBaseDir
|
313
|
+
!db || pr("perform_encrypt, enc_dir set to repoBaseDir #{@repoBaseDir}\n")
|
308
314
|
end
|
309
315
|
|
310
316
|
setInputOutputDirs(@startDir,enc_dir)
|
@@ -317,7 +323,7 @@ module LEnc
|
|
317
323
|
puts("Encrypting...") if @verbosity >= 1
|
318
324
|
|
319
325
|
begin
|
320
|
-
|
326
|
+
encrypt_directory_contents(@repoBaseDir, enc_dir)
|
321
327
|
puts("...done.") if @verbosity >= 1
|
322
328
|
end
|
323
329
|
end
|
@@ -763,8 +769,10 @@ module LEnc
|
|
763
769
|
end
|
764
770
|
|
765
771
|
temp_enc_path = convertFile(sourceFile, true, showProgress)
|
772
|
+
!db || pr(" converted [#{sourceFile}] to temp [#{temp_enc_path}]\n")
|
766
773
|
if not @dryrun
|
767
774
|
FileUtils.mv(temp_enc_path, encryptFile)
|
775
|
+
!db || pr(" moved temp to encryptFile #{encryptFile}\n")
|
768
776
|
end
|
769
777
|
|
770
778
|
end
|
@@ -822,9 +830,9 @@ module LEnc
|
|
822
830
|
# @param sourceDir absolute path of source directory
|
823
831
|
# @param encryptDir absolute path of encryption directory
|
824
832
|
#
|
825
|
-
def
|
833
|
+
def encrypt_directory_contents(sourceDir, encryptDir)
|
826
834
|
|
827
|
-
db =
|
835
|
+
db = warndb 0
|
828
836
|
|
829
837
|
!db || pr("\n\nencryptDir\n %s =>\n %s\n",d(sourceDir),d(encryptDir))
|
830
838
|
|
@@ -869,6 +877,7 @@ module LEnc
|
|
869
877
|
# Examine each file in source dir
|
870
878
|
dirc = dir_entries(sourceDir)
|
871
879
|
|
880
|
+
!db || pr(" dirc=%s\n",d2(dirc))
|
872
881
|
dirc.each do |f2|
|
873
882
|
# Convert string to ASCII-8BIT encoding.
|
874
883
|
f = to_ascii8(f2)
|
@@ -909,7 +918,7 @@ module LEnc
|
|
909
918
|
encrPath = File.join(encryptDir, encrName)
|
910
919
|
|
911
920
|
if File.directory?(filePath)
|
912
|
-
|
921
|
+
encrypt_directory_contents(filePath, encrPath)
|
913
922
|
else
|
914
923
|
!db || pr("...attempting to encrypt file #{filePath} to #{encrPath}...\n")
|
915
924
|
encrypt_file(filePath, encrPath)
|
@@ -924,16 +933,17 @@ module LEnc
|
|
924
933
|
end
|
925
934
|
|
926
935
|
if File.directory?(filePath)
|
927
|
-
|
936
|
+
encrypt_directory_contents(filePath, filePath)
|
928
937
|
# Rename the directory to its encrypted form, if necessary
|
929
|
-
if filePath != encrPath
|
938
|
+
if (not @dryrun) && (filePath != encrPath)
|
930
939
|
!db || pr(" renaming now-encrypted file from\n #{filePath}\n to\n #{encrPath}\n")
|
931
940
|
FileUtils.mv(filePath,encrPath)
|
932
941
|
end
|
933
942
|
else
|
934
943
|
encrypt_file(filePath, encrPath)
|
935
944
|
# Delete unencrypted file, if not using original names
|
936
|
-
if
|
945
|
+
if (not @dryrun) && (not @orignames)
|
946
|
+
!db || pr(" attempting to remove unencrypted file #{filePath}\n")
|
937
947
|
FileUtils.rm(filePath)
|
938
948
|
end
|
939
949
|
end
|
@@ -968,7 +978,7 @@ module LEnc
|
|
968
978
|
printf("Removing encrypted version of missing (or ignored) file " \
|
969
979
|
+ rel_path(File.join(sourceDir, orphanOrigName), @inputDir) + ": " + orphanPath)
|
970
980
|
end
|
971
|
-
if
|
981
|
+
if not @dryrun
|
972
982
|
remove_file_or_dir(orphanPath)
|
973
983
|
end
|
974
984
|
rescue DecryptionError
|
@@ -1035,9 +1045,11 @@ module LEnc
|
|
1035
1045
|
if !@orignames
|
1036
1046
|
raise ArgumentError,"decrypted already exists: #{decrPath}" \
|
1037
1047
|
if File.exist?(decrPath)
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1048
|
+
|
1049
|
+
if not @dryrun
|
1050
|
+
!db || pr(" renaming now-decrypted directory from\n #{filePath}\n to\n #{decrPath}\n")
|
1051
|
+
FileUtils.mv(filePath,decrPath)
|
1052
|
+
end
|
1041
1053
|
end
|
1042
1054
|
else
|
1043
1055
|
decrPathDisp = File.join(decr_dir_name,decrName)
|
@@ -1084,7 +1096,9 @@ module LEnc
|
|
1084
1096
|
if File.file?(recoverDir)
|
1085
1097
|
raise RecoveryError, "Cannot replace existing file '" + recoverDir + "' with directory"
|
1086
1098
|
end
|
1087
|
-
|
1099
|
+
if not @dryrun
|
1100
|
+
Dir.mkdir(recoverDir)
|
1101
|
+
end
|
1088
1102
|
end
|
1089
1103
|
|
1090
1104
|
if not File.directory?(encryptDir)
|
@@ -1196,7 +1210,7 @@ module LEnc
|
|
1196
1210
|
|
1197
1211
|
fr = File.open(srcPath, 'rb')
|
1198
1212
|
fw = Tempfile.new("repo")
|
1199
|
-
|
1213
|
+
!db || pr("created temporary file #{fw.path}\n")
|
1200
1214
|
cSize = 100000
|
1201
1215
|
|
1202
1216
|
# Predict number of chunks required
|
@@ -1256,6 +1270,7 @@ module LEnc
|
|
1256
1270
|
pr("\n")
|
1257
1271
|
end
|
1258
1272
|
|
1273
|
+
!db || pr(" (done convertFile)\n")
|
1259
1274
|
fw
|
1260
1275
|
end
|
1261
1276
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lenc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeff Sember
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-05-
|
11
|
+
date: 2013-05-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: highline
|
@@ -39,7 +39,6 @@ extensions: []
|
|
39
39
|
extra_rdoc_files: []
|
40
40
|
files:
|
41
41
|
- lib/lenc.rb
|
42
|
-
- lib/lenc/_OLD_tools.rb
|
43
42
|
- lib/lenc/aes.rb
|
44
43
|
- lib/lenc/config_file.rb
|
45
44
|
- lib/lenc/encr.rb
|
data/lib/lenc/_OLD_tools.rb
DELETED
@@ -1,628 +0,0 @@
|
|
1
|
-
require 'set'
|
2
|
-
require 'fileutils'
|
3
|
-
|
4
|
-
# Various utility and debug convenience functions.
|
5
|
-
#
|
6
|
-
|
7
|
-
# Convenience method to perform 'require_relative' on a set of files
|
8
|
-
#
|
9
|
-
# @param fileListStr space-delimited file/path items, without .rb extensions
|
10
|
-
# @param subdir optional path to files relative to this file
|
11
|
-
#
|
12
|
-
def req(fileListStr,subdir = nil)
|
13
|
-
fileListStr.split(' ').each do |x|
|
14
|
-
if subdir
|
15
|
-
x = File.join(subdir,x)
|
16
|
-
end
|
17
|
-
x += '.rb'
|
18
|
-
require_relative(x)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
# Shorthand for printf(...)
|
23
|
-
# @param args passed to printf
|
24
|
-
def pr(*args)
|
25
|
-
printf(*args)
|
26
|
-
end
|
27
|
-
|
28
|
-
# Convert an object to a human-readable string,
|
29
|
-
# or <nil>; should be considered a debug-only feature
|
30
|
-
#
|
31
|
-
def d(arg)
|
32
|
-
arg.nil? ? "<nil>" : arg.inspect
|
33
|
-
end
|
34
|
-
|
35
|
-
# Convert an object to a human-readable string,
|
36
|
-
# by calling a type-appropriate function: da, dh, or just d.
|
37
|
-
# @param arg object
|
38
|
-
# @param indent optional indentation for pretty printing; if result
|
39
|
-
# spans multiple lines, each line should be indented by this amount
|
40
|
-
#
|
41
|
-
def d2(arg, indent = 0)
|
42
|
-
return da(arg, indent) if arg.is_a? Array
|
43
|
-
return dh(arg, indent) if arg.is_a? Hash
|
44
|
-
return df(arg) if arg.class == FalseClass || arg.class == TrueClass
|
45
|
-
return d(arg)
|
46
|
-
end
|
47
|
-
|
48
|
-
# Convert an object to a human-readable string, prefixed with its type
|
49
|
-
#
|
50
|
-
def dt(arg)
|
51
|
-
if arg.nil?
|
52
|
-
return "<nil>"
|
53
|
-
end
|
54
|
-
s = arg.class.to_s
|
55
|
-
s << ':'
|
56
|
-
s << arg.inspect
|
57
|
-
s
|
58
|
-
end
|
59
|
-
|
60
|
-
# Append a particular number of spaces to a string
|
61
|
-
def add_sp(s, indent = 0)
|
62
|
-
s << ' ' * indent
|
63
|
-
end
|
64
|
-
|
65
|
-
# Pretty-print an array,
|
66
|
-
# one element to a line
|
67
|
-
# @param indent indentation of each line, in spaces
|
68
|
-
def da(array, indent = 0)
|
69
|
-
return d(array) if !array
|
70
|
-
s = 'Array ['
|
71
|
-
indent += 2
|
72
|
-
array.each do |x|
|
73
|
-
s << "\n"
|
74
|
-
add_sp(s,indent)
|
75
|
-
s2 = d2(x, indent + 2)
|
76
|
-
s << s2
|
77
|
-
end
|
78
|
-
s << " ]"
|
79
|
-
s
|
80
|
-
end
|
81
|
-
|
82
|
-
# Pretty-print a hash,
|
83
|
-
# one element to a line
|
84
|
-
# @param indent indentation of each line, in spaces
|
85
|
-
def dh(hash, indent = 0)
|
86
|
-
return d(hash) if !hash
|
87
|
-
s = 'Hash {'
|
88
|
-
indent += 2
|
89
|
-
hash.each_pair do |key,val|
|
90
|
-
s2 = d(key)
|
91
|
-
s3 = d2(val, indent + 4)
|
92
|
-
s << "\n "
|
93
|
-
add_sp(s,indent)
|
94
|
-
s << s2.chomp << " => " << s3.chomp
|
95
|
-
end
|
96
|
-
s << " }"
|
97
|
-
s
|
98
|
-
end
|
99
|
-
|
100
|
-
# Generate debug description of a boolean value
|
101
|
-
# @param flag value to interpret as a boolean; prints 'T' iff not nil
|
102
|
-
# @param label optional label
|
103
|
-
def df(flag, label=nil)
|
104
|
-
s = ''
|
105
|
-
if label
|
106
|
-
s << label << ':'
|
107
|
-
end
|
108
|
-
s << (flag ? "T" : "F")
|
109
|
-
s << ' '
|
110
|
-
s
|
111
|
-
end
|
112
|
-
|
113
|
-
# Assert that a value is true. Should be considered a
|
114
|
-
# very temporary, debug-only option; it is slow and
|
115
|
-
# generates a warning that it is being called.
|
116
|
-
# @param cond condition
|
117
|
-
# @param msg generates additional message using printf(), if these arguments exist
|
118
|
-
def assert!(cond, *msg)
|
119
|
-
one_time_alert("warning",0,"Checking assertion")
|
120
|
-
if not cond
|
121
|
-
str = (msg.size == 0) ? "assertion error" : sprintf(*msg)
|
122
|
-
raise Exception, str
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
# Extensions to the Enumerable module
|
127
|
-
#
|
128
|
-
module Enumerable
|
129
|
-
# Calculate a value for each item, and return the item with the
|
130
|
-
# highest value, its index, and the value.
|
131
|
-
# @yieldparam function to calculate value of an object, given that object as a parameter
|
132
|
-
# @return the triple [object, index, value] reflecting the maximum value, or
|
133
|
-
# nil if there were no items
|
134
|
-
def max_with_index
|
135
|
-
|
136
|
-
best = nil
|
137
|
-
|
138
|
-
each_with_index do |obj,ind|
|
139
|
-
sc = yield(obj)
|
140
|
-
if !best || best[2] < sc
|
141
|
-
best = [obj,ind,sc]
|
142
|
-
end
|
143
|
-
end
|
144
|
-
best
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
# Get a nice, concise description of the file and line
|
149
|
-
# of some caller within the stack.
|
150
|
-
#
|
151
|
-
# @param nSkip the number of items deep in the call stack to look
|
152
|
-
#
|
153
|
-
def get_caller_location(nSkip = 2)
|
154
|
-
|
155
|
-
filename = nil
|
156
|
-
linenumber = nil
|
157
|
-
|
158
|
-
if nSkip >= 0 && nSkip < caller.size
|
159
|
-
fi = caller[nSkip]
|
160
|
-
|
161
|
-
i = fi.index(':')
|
162
|
-
j = nil
|
163
|
-
if i
|
164
|
-
j = fi.index(':',i+1)
|
165
|
-
end
|
166
|
-
if j
|
167
|
-
pth = fi[0,i].split('/')
|
168
|
-
if pth.size
|
169
|
-
filename = pth[-1]
|
170
|
-
end
|
171
|
-
linenumber = fi[i+1,j-i-1]
|
172
|
-
end
|
173
|
-
end
|
174
|
-
if filename && linenumber
|
175
|
-
loc = filename + " ("+linenumber+")"
|
176
|
-
else
|
177
|
-
loc = "(UNKNOWN LOCATION)"
|
178
|
-
end
|
179
|
-
loc
|
180
|
-
end
|
181
|
-
|
182
|
-
# Set of alert strings that have already been reported
|
183
|
-
# (to avoid printing anything on subsequent invocations)
|
184
|
-
#
|
185
|
-
$AlertStrings = Set.new
|
186
|
-
|
187
|
-
# Print a message if it hasn't yet been printed,
|
188
|
-
# which includes the caller's location
|
189
|
-
#
|
190
|
-
# @param typeString e.g., "warning", "unimplemented"
|
191
|
-
# @param nSkip the number of levels deep that the caller is in the stack
|
192
|
-
# @param args if present, calls sprintf(...) with these to append to the message
|
193
|
-
#
|
194
|
-
def one_time_alert(typeString, nSkip, *args)
|
195
|
-
loc = get_caller_location(nSkip + 2)
|
196
|
-
s = "*** "+typeString+" " + loc
|
197
|
-
if args && args.size
|
198
|
-
s2 = sprintf(args[0], *args[1..-1])
|
199
|
-
msg = s + ": " + s2
|
200
|
-
else
|
201
|
-
msg = s
|
202
|
-
end
|
203
|
-
|
204
|
-
if $AlertStrings.add?(msg)
|
205
|
-
puts msg
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
# Print a 'warning' alert, one time only
|
210
|
-
# @param args if present, calls printf() with these
|
211
|
-
def warn(*args)
|
212
|
-
one_time_alert("warning",0, *args)
|
213
|
-
end
|
214
|
-
|
215
|
-
# Convenience method for setting 'db' true within methods,
|
216
|
-
# and to print a one-time warning if so.
|
217
|
-
# @param val value to set db to; it is convenient to disable
|
218
|
-
# debug printing quickly by adding a zero, e.g., 'warndb 0'
|
219
|
-
#
|
220
|
-
def warndb(val = true)
|
221
|
-
if !val || val == 0
|
222
|
-
return false
|
223
|
-
end
|
224
|
-
one_time_alert("warning",1, "Debug printing enabled")
|
225
|
-
true
|
226
|
-
end
|
227
|
-
|
228
|
-
# Print an 'unimplemented' alert, one time only
|
229
|
-
# @param args if present, calls printf() with these
|
230
|
-
def unimp(*args)
|
231
|
-
one_time_alert("unimplemented", 0, *args)
|
232
|
-
end
|
233
|
-
|
234
|
-
# Write a string to a text file
|
235
|
-
#
|
236
|
-
def write_text_file(path, contents)
|
237
|
-
File.open(path, "wb") {|f| f.write(contents) }
|
238
|
-
end
|
239
|
-
|
240
|
-
# Read a file's contents, return as a string
|
241
|
-
#
|
242
|
-
def read_text_file(path)
|
243
|
-
contents = nil
|
244
|
-
File.open(path,"rb") {|f| contents = f.read }
|
245
|
-
contents
|
246
|
-
end
|
247
|
-
|
248
|
-
# Method that takes a code block as an argument to
|
249
|
-
# achieve the same functionality as Java/C++'s
|
250
|
-
# do {
|
251
|
-
# ...
|
252
|
-
# ... possibly with 'break' to jump to the end ...
|
253
|
-
# } while (false);
|
254
|
-
#
|
255
|
-
def block
|
256
|
-
yield
|
257
|
-
end
|
258
|
-
|
259
|
-
# Exception class for objects in illegal states
|
260
|
-
#
|
261
|
-
class IllegalStateException < Exception
|
262
|
-
end
|
263
|
-
|
264
|
-
def to_hex(value, num_digits=4)
|
265
|
-
s = sprintf("%x", value)
|
266
|
-
s.rjust(num_digits,'0')
|
267
|
-
end
|
268
|
-
|
269
|
-
def hex_dump(byte_array_or_string, title=nil, offset=0, length= -1, bytes_per_row=16, with_text=true)
|
270
|
-
ss = hex_dump_to_string(byte_array_or_string, title, offset, length, bytes_per_row, with_text)
|
271
|
-
puts ss
|
272
|
-
end
|
273
|
-
|
274
|
-
def hex_dump_to_string(byte_array_or_string, title=nil, offset=0, length= -1, bytes_per_row=16, with_text=true)
|
275
|
-
|
276
|
-
byte_array = byte_array_or_string
|
277
|
-
if byte_array.is_a? String
|
278
|
-
byte_array = byte_array.bytes.to_a
|
279
|
-
end
|
280
|
-
|
281
|
-
ss = ''
|
282
|
-
|
283
|
-
if title
|
284
|
-
ss << title << ":\n"
|
285
|
-
end
|
286
|
-
|
287
|
-
if length < 0
|
288
|
-
length = byte_array.size - offset
|
289
|
-
end
|
290
|
-
|
291
|
-
length = [length, byte_array.size - offset].min
|
292
|
-
|
293
|
-
max_addr = offset + length - 1
|
294
|
-
num_digits = 4
|
295
|
-
while (1 << (4 * num_digits)) <= max_addr
|
296
|
-
num_digits += 1
|
297
|
-
end
|
298
|
-
|
299
|
-
while true
|
300
|
-
ss << to_hex(offset, num_digits)
|
301
|
-
ss << ': '
|
302
|
-
|
303
|
-
chunk = [length, bytes_per_row].min
|
304
|
-
bytes_per_row.times do |i|
|
305
|
-
if i % 4 == 0
|
306
|
-
ss << ' '
|
307
|
-
end
|
308
|
-
|
309
|
-
if i < chunk
|
310
|
-
v = byte_array[offset + i]
|
311
|
-
ss << ((v != 0) ? to_hex(v,2) : '..')
|
312
|
-
ss << ' '
|
313
|
-
else
|
314
|
-
ss << ' '
|
315
|
-
end
|
316
|
-
|
317
|
-
end
|
318
|
-
|
319
|
-
|
320
|
-
if with_text
|
321
|
-
ss << ' |'
|
322
|
-
bytes_per_row.times do |i|
|
323
|
-
if i < chunk
|
324
|
-
v = byte_array[offset + i]
|
325
|
-
ss << ((v >= 32 && v < 127) ? v : '_')
|
326
|
-
end
|
327
|
-
end
|
328
|
-
ss << '|'
|
329
|
-
end
|
330
|
-
ss << "\n"
|
331
|
-
|
332
|
-
length -= chunk
|
333
|
-
offset += chunk
|
334
|
-
break if length <= 0
|
335
|
-
end
|
336
|
-
|
337
|
-
ss << "\n"
|
338
|
-
ss
|
339
|
-
end
|
340
|
-
|
341
|
-
$prevTime = nil
|
342
|
-
|
343
|
-
# Calculate time elapsed, in seconds, from last call to this function;
|
344
|
-
# if it's never been called, returns zero
|
345
|
-
def elapsed
|
346
|
-
curr = Time.now.to_f
|
347
|
-
elap = 0
|
348
|
-
if $prevTime
|
349
|
-
elap = curr - $prevTime
|
350
|
-
end
|
351
|
-
$prevTime = curr
|
352
|
-
elap
|
353
|
-
end
|
354
|
-
|
355
|
-
# Delete a file or directory, if it exists.
|
356
|
-
# Caution! If directory, deletes all files and subdirectories.
|
357
|
-
def remove_file_or_dir(pth)
|
358
|
-
if File.directory?(pth)
|
359
|
-
FileUtils.remove_dir(pth)
|
360
|
-
elsif File.file?(pth)
|
361
|
-
FileUtils.remove_file(pth)
|
362
|
-
end
|
363
|
-
end
|
364
|
-
|
365
|
-
require 'stringio'
|
366
|
-
|
367
|
-
$IODest = nil
|
368
|
-
$OldStdOut = nil
|
369
|
-
|
370
|
-
def capture_begin
|
371
|
-
raise IllegalStateException if $IODest
|
372
|
-
$IODest = StringIO.new
|
373
|
-
$OldStdOut, $stdout = $stdout, $IODest
|
374
|
-
end
|
375
|
-
|
376
|
-
def capture_end
|
377
|
-
raise IllegalStateException if !$IODest
|
378
|
-
$stdout = $OldStdOut
|
379
|
-
ret = $IODest.string
|
380
|
-
$IODest = nil
|
381
|
-
ret
|
382
|
-
end
|
383
|
-
|
384
|
-
def match_expected_output(str = nil)
|
385
|
-
|
386
|
-
if !str
|
387
|
-
str = capture_end
|
388
|
-
end
|
389
|
-
|
390
|
-
cl_method = caller[0][/`.*'/][1..-2]
|
391
|
-
if (cl_method.start_with?("test_"))
|
392
|
-
cl_method = cl_method[5..-1]
|
393
|
-
end
|
394
|
-
path = "_output_" + cl_method + ".txt"
|
395
|
-
# path = File.absolute_path(path)
|
396
|
-
|
397
|
-
if !File.file?(path)
|
398
|
-
printf("no such file #{path} exists, writing it...\n")
|
399
|
-
writeTextFile(path,str)
|
400
|
-
else
|
401
|
-
exp_cont = read_text_file(path)
|
402
|
-
if str != exp_cont
|
403
|
-
d1 = str
|
404
|
-
d2 = exp_cont
|
405
|
-
# d1 = hex_dump_to_string(str,"Output")
|
406
|
-
# d2 = hex_dump_to_string(exp_cont,"Expected")
|
407
|
-
|
408
|
-
raise IllegalStateException,"output did not match expected:\n#{d1}#{d2}"
|
409
|
-
end
|
410
|
-
end
|
411
|
-
end
|
412
|
-
|
413
|
-
# Convenience method to detect if a script is being run
|
414
|
-
# e.g. as a 'main' method (for debug purposes only).
|
415
|
-
# If so, it changes the current directory to the
|
416
|
-
# directory containing the script (if such a directory exists).
|
417
|
-
#
|
418
|
-
# @param file pass __FILE__ in here
|
419
|
-
# @return true if so
|
420
|
-
#
|
421
|
-
def main?(file)
|
422
|
-
|
423
|
-
scr = $0
|
424
|
-
|
425
|
-
# The test/unit framework seems to be adding a suffix ": xxx#xxx.."
|
426
|
-
# to the .rb filename, so adjust in this case
|
427
|
-
i = scr.index(".rb: ")
|
428
|
-
if i
|
429
|
-
scr = scr[0...i+3]
|
430
|
-
end
|
431
|
-
|
432
|
-
if (ret = (file == scr))
|
433
|
-
dr = File.dirname(file)
|
434
|
-
if File.directory?(dr)
|
435
|
-
Dir.chdir(dr)
|
436
|
-
end
|
437
|
-
end
|
438
|
-
ret
|
439
|
-
end
|
440
|
-
|
441
|
-
if defined? Test::Unit
|
442
|
-
|
443
|
-
# A simple extension to Ruby's Test::Unit class that provides
|
444
|
-
# suite-level setup/teardown methods.
|
445
|
-
#
|
446
|
-
# If test suite functionality is desired within a script,
|
447
|
-
# then require 'test/unit' before requiring 'tools.rb'.
|
448
|
-
# This will cause the following class, MyTestSuite, to be defined.
|
449
|
-
#
|
450
|
-
# The user's test script can define subclasses of this,
|
451
|
-
# and declare test methods with the name 'test_xxxx', where
|
452
|
-
# xxxx is lexicographically between 01 and zz.
|
453
|
-
#
|
454
|
-
# There are two levels of setup/teardown called : suite level, and
|
455
|
-
# method level. For example, if the user's test class performs two tests:
|
456
|
-
#
|
457
|
-
# def test_b ... end
|
458
|
-
# def test_c ... end
|
459
|
-
#
|
460
|
-
# Then the test framework will make these calls:
|
461
|
-
#
|
462
|
-
# suite_setup
|
463
|
-
#
|
464
|
-
# method_setup
|
465
|
-
# test_b
|
466
|
-
# method_teardown
|
467
|
-
#
|
468
|
-
# method_setup
|
469
|
-
# test_c
|
470
|
-
# method_teardown
|
471
|
-
#
|
472
|
-
# suite_teardown
|
473
|
-
#
|
474
|
-
# Notes
|
475
|
-
# -----
|
476
|
-
# 1) The usual setup / teardown methods should NOT be overridden; instead,
|
477
|
-
# use the method_xxx alternatives.
|
478
|
-
#
|
479
|
-
# 2) The base class implementations of method_/suite_xxx do nothing.
|
480
|
-
#
|
481
|
-
# 3) The number of test cases reported may be higher than you expect, since
|
482
|
-
# there are additional test methods defined by the TestSuite class to
|
483
|
-
# implement the suite setup / teardown functionality.
|
484
|
-
#
|
485
|
-
# 4) Avoid naming test methods that fall outside of test_01 ... test_zz.
|
486
|
-
#
|
487
|
-
class MyTestSuite < Test::Unit::TestCase
|
488
|
-
|
489
|
-
# This is named to be the FIRST test called. It
|
490
|
-
# will do suite-level setup, and nothing else.
|
491
|
-
def test_00_setup
|
492
|
-
@@suiteSetup = true
|
493
|
-
suite_setup()
|
494
|
-
end
|
495
|
-
|
496
|
-
# This is named to be the LAST test called. It
|
497
|
-
# will do suite-level teardown, and nothing else.
|
498
|
-
def test_zzzzzz_teardown
|
499
|
-
suite_teardown()
|
500
|
-
@@suiteSetup = false
|
501
|
-
end
|
502
|
-
|
503
|
-
# True if called within suite-level setup/teardown window
|
504
|
-
def _suite_active?
|
505
|
-
!(@__name__ == "test_00_setup" || @__name__ == "test_zzzzzz_teardown")
|
506
|
-
end
|
507
|
-
|
508
|
-
def setup
|
509
|
-
if _suite_active?
|
510
|
-
# If only a specific test was requested, the
|
511
|
-
# suite setup may not have run... if not, do it now.
|
512
|
-
if !defined? @@suiteSetup
|
513
|
-
suite_setup
|
514
|
-
end
|
515
|
-
return
|
516
|
-
end
|
517
|
-
method_setup
|
518
|
-
end
|
519
|
-
|
520
|
-
def teardown
|
521
|
-
if _suite_active?
|
522
|
-
if !defined? @@suiteSetup
|
523
|
-
suite_teardown
|
524
|
-
end
|
525
|
-
return
|
526
|
-
end
|
527
|
-
method_teardown
|
528
|
-
end
|
529
|
-
|
530
|
-
def suite_setup
|
531
|
-
end
|
532
|
-
|
533
|
-
def suite_teardown
|
534
|
-
end
|
535
|
-
|
536
|
-
def method_setup
|
537
|
-
end
|
538
|
-
|
539
|
-
def method_teardown
|
540
|
-
end
|
541
|
-
end
|
542
|
-
end
|
543
|
-
|
544
|
-
# Construct a string from an array of bytes
|
545
|
-
# @param byte_array array of bytes, or string (in which case it
|
546
|
-
# returns it unchanged)
|
547
|
-
#
|
548
|
-
def bytes_to_str(byte_array)
|
549
|
-
return byte_array if byte_array.is_a? String
|
550
|
-
|
551
|
-
byte_array.pack('C*')
|
552
|
-
end
|
553
|
-
|
554
|
-
# Construct an array of bytes from a string
|
555
|
-
# @param str string, or array of bytes (in which case it
|
556
|
-
# returns it unchanged)
|
557
|
-
#
|
558
|
-
def str_to_bytes(str)
|
559
|
-
return str if str.is_a? Array
|
560
|
-
str.bytes
|
561
|
-
end
|
562
|
-
|
563
|
-
# Get directory entries, excluding '.' and '..'
|
564
|
-
#
|
565
|
-
def dir_entries(path)
|
566
|
-
ents = Dir.entries(path)
|
567
|
-
ents.reject!{|entry| entry == '.' || entry == '..'}
|
568
|
-
end
|
569
|
-
|
570
|
-
def int_to_bytes(x)
|
571
|
-
[(x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff]
|
572
|
-
end
|
573
|
-
|
574
|
-
def short_to_bytes(x)
|
575
|
-
[(x >> 8) & 0xff, x & 0xff]
|
576
|
-
end
|
577
|
-
|
578
|
-
# Decode a short from an array of bytes (big-endian).
|
579
|
-
# @param ba array of bytes
|
580
|
-
# @param offset offset of first (most significant) byte
|
581
|
-
#
|
582
|
-
def short_from_bytes(ba, offset=0)
|
583
|
-
(ba[offset] << 8) | ba[offset + 1]
|
584
|
-
end
|
585
|
-
|
586
|
-
# Decode an int from an array of bytes (big-endian).
|
587
|
-
# @param ba array of bytes
|
588
|
-
# @param offset offset of first (most significant) byte
|
589
|
-
#
|
590
|
-
def int_from_bytes(ba, offset=0)
|
591
|
-
(((((ba[offset] << 8) | ba[offset + 1]) << 8) | \
|
592
|
-
ba[offset + 2]) << 8) | ba[offset + 3]
|
593
|
-
end
|
594
|
-
|
595
|
-
# Transform string to 8-bit ASCII (i.e., just treat each byte as-is)
|
596
|
-
#
|
597
|
-
def to_ascii8(str)
|
598
|
-
str.force_encoding("ASCII-8BIT")
|
599
|
-
end
|
600
|
-
|
601
|
-
# Verify that a string is encoded as ASCII-8BIT
|
602
|
-
def simple_str(s)
|
603
|
-
if s.encoding.name != 'ASCII-8BIT' && s.encoding.name != 'UTF-8'
|
604
|
-
pr("string [%s]\n encoding is %s,\n expected ASCII-8BIT\n",s,s.encoding.name)
|
605
|
-
assert!(false)
|
606
|
-
end
|
607
|
-
end
|
608
|
-
|
609
|
-
# Truncate or pad string so it has a particular size
|
610
|
-
#
|
611
|
-
# @param s input string
|
612
|
-
# @param size
|
613
|
-
# @param pad padding character to use if string needs to grow
|
614
|
-
# @return modified string
|
615
|
-
#
|
616
|
-
def str_sized(s, size, pad="\0")
|
617
|
-
s[0...size].ljust(size,pad)
|
618
|
-
end
|
619
|
-
|
620
|
-
# Determine if running on the Windows operating system.
|
621
|
-
# Note: there is some debate about the best way to do this.
|
622
|
-
#
|
623
|
-
def windows?
|
624
|
-
if !defined? $__windows__
|
625
|
-
$__windows__ = (RUBY_PLATFORM =~ /mswin/)
|
626
|
-
end
|
627
|
-
$__windows__
|
628
|
-
end
|