1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
# test type conversion and error handling in entab/detab
procedure main ()
s := "rutabaga"
if entab('1987') ~== "1789" then write ("oops 1")
if detab('1492') ~== "1249" then write ("oops 2")
if entab(" ","3") ~== "\t\t" then write ("oops 3")
if detab("\t\t","3") ~== " " then write ("oops 4")
ferr (103, entab, [])
ferr (103, detab, [])
ferr (103, entab, [[]])
ferr (103, detab, [[]])
ferr (101, entab, [s,2,3,&lcase])
ferr (101, detab, [s,4,5,&ucase])
ferr (210, entab, [s,7,4])
ferr (210, entab, [s,6,6])
ferr (210, detab, [s,8,5])
ferr (210, detab, [s,3,3])
endetab1()
end
# ferr(err,func,arglst) -- call func(args), verify that error "err" is produced
procedure ferr (err, func, args)
local val
val := ""
every val ||:= image(!args) || ","
val := val[1:-1]
msg := "oops -- " || image(func) || "(" || val || ") "
&error := 1
if func!args
then write (msg, "succeeded")
else if &error ~= 0
then write (msg, "failed but no error")
else if &errornumber ~= err
then write (msg, "got error ",&errornumber," instead of ",err)
&error := 0
return
end
## Test driver for entab and detab
#
# Input is read from standard input. Commentary and error reports go to
# standard output.
#
# Input lines are first preprocessed by interpreting escape sequences \a, \b,
# \n, \r, and \t and trimming a trailing '$' character.
#
# Input lines beginning with "=" establish tab stop settings. Each numeric
# field specifies a tab stop, according to the entab/detab specs.
#
# All other lines are passed through entab and then detab, and the results are
# checked. The characters "!" and "." are replaced by spaces before calling
# entab; "!" positions are expected to be replaced by tabs, with "." positions
# disappearing. For example, "abcd!...ijk" tests that entab("abcd ijk")
# returns "abcd\tijk".
#
# The result of each entab call is then passed to detab, with results expected
# to match the original entab argument (or its detab, if it had any tabs).
procedure endetab1 ()
params := setup ("=") # start with default tabs (no args)
while line := escape (read ()) do { # read and preprocess line
if line[1] == "=" then
params := setup (line) # '=' line sets tab stops (arg list)
else {
s := map (line, "!.", " ") # turn "!." characters into spaces
params[1] := s
t := invoke (entab, params) # run entab
if t ~== interp (line) then { # check results
write ("entab failed for: ", map(line,"\t\r\n\b\007","!RNBA"))
write (" returned value: ", map(t, "\t\r\n\b\007","!RNBA"))
} else {
if upto ('\t', s) then # detab input if it had a tab
s := invoke (detab, params)
params[1] := t
t := invoke (detab, params) # detab the result of the entab
if t ~== s then { # compare results
write ("detab failed for: ", map(line,"\t\r\n\b\007","!RNBA"))
write (" returned value: ", map(t, "\t\r\n\b\007","!RNBA"))
}
}
}
}
end
procedure escape (line) # interpret escape sequences and trim one '$'
if line[-1] == "$" then
line := line[1:-1]
s := ""
line ?
while not pos (0) do {
s ||:= tab (upto ('\\') | 0)
s ||:= (="\\" & case (c := move(1)) of {
"a": "\007"
"b": "\b"
"n": "\n"
"r": "\r"
"t": "\t"
default: "\\" || c
})
}
return s
end
procedure interp (pattern) # interpret metacharacters '!.'
s := ""
pattern ?
while not pos (0) do {
tab (many ('.'))
s ||:= tab (upto ('.') | 0)
}
return map (s, "!", "\t")
end
procedure setup (line) # interpret and report a column spec line
p := [&null]
line ? while tab (upto (&digits)) do
put (p, integer (tab (many (&digits))))
writes ("testing entab/detab(s")
every writes (",", \!p)
write (")")
return p
end
procedure invoke (func, a) # invoke a function with a list of up to 10 args
return case *a of {
0: func ()
1: func (a[1])
2: func (a[1], a[2])
3: func (a[1], a[2], a[3])
4: func (a[1], a[2], a[3], a[4])
5: func (a[1], a[2], a[3], a[4], a[5])
6: func (a[1], a[2], a[3], a[4], a[5], a[6])
7: func (a[1], a[2], a[3], a[4], a[5], a[6], a[7])
8: func (a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8])
9: func (a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9])
10: func (a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10])
default: stop ("too many args for invoke")
}
end
|