aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDiego Nehab <diego@tecgraf.puc-rio.br>2004-11-28 00:59:12 +0000
committerDiego Nehab <diego@tecgraf.puc-rio.br>2004-11-28 00:59:12 +0000
commit05e8f243851049cebda6c5b690d3cde0f1e2c874 (patch)
tree9799a322fee3aefb07eaafa00875f214ad2b7ea6
parent50da56dbeeec0cc7856ac06057cb778b502e087b (diff)
downloadluasocket-05e8f243851049cebda6c5b690d3cde0f1e2c874.tar.gz
luasocket-05e8f243851049cebda6c5b690d3cde0f1e2c874.tar.bz2
luasocket-05e8f243851049cebda6c5b690d3cde0f1e2c874.zip
New LTN12 test procedures (still short, but growing)
LTN12 avoids coroutines.
-rw-r--r--FIX1
-rw-r--r--src/ltn12.lua131
-rw-r--r--src/wsocket.c2
-rw-r--r--test/ltn12test.lua275
-rw-r--r--test/mimetest.lua36
5 files changed, 334 insertions, 111 deletions
diff --git a/FIX b/FIX
index a7f244f..5ce3a01 100644
--- a/FIX
+++ b/FIX
@@ -1,3 +1,4 @@
1ltn12 avoids coroutines (so you can go wild on the C side)
1automated tests for ftp now in use 2automated tests for ftp now in use
2new compat-5.1 distribution 3new compat-5.1 distribution
3 instalation should use new directory structure 4 instalation should use new directory structure
diff --git a/src/ltn12.lua b/src/ltn12.lua
index 43c2755..5216ff6 100644
--- a/src/ltn12.lua
+++ b/src/ltn12.lua
@@ -35,64 +35,40 @@ function filter.cycle(low, ctx, extra)
35 end 35 end
36end 36end
37 37
38--[[ 38-- chains a bunch of filters together
39local function chain2(f1, f2) 39-- (thanks to Wim Couwenberg)
40 local ff1, ff2 = "", "" 40function filter.chain(...)
41 local n = table.getn(arg)
42 local top, index = 1, 1
41 return function(chunk) 43 return function(chunk)
42 local rf1 = chunk and "" 44 while true do
43 local rf2 = ff1 and "" 45 if index == top then
44 -- if f2 still has pending data, get it and return it 46 chunk = arg[index](chunk)
45 if ff2 ~= rf2 then 47 if chunk == "" or top == n then
46 ff2 = f2(rf2) 48 return chunk
47 if ff2 ~= "" then return ff2 end 49 elseif chunk then
48 end 50 index = index + 1
49 -- here we know f2 needs more data 51 else
50 -- we try to get it from f1 52 top = top+1
51 ff1 = f1(chunk) 53 index = top
52 while 1 do 54 end
53 -- if f1 can't produce data, we need more data from the user 55 else
54 if ff1 == "" then return "" end 56 local original = chunk
55 -- otherwise we pass new data to f2 until it produces something 57 chunk = arg[index](original or "")
56 -- or f1 runs out of data too 58 if chunk == "" then
57 ff2 = f2(ff1) 59 index = index - 1
58 if ff2 ~= "" then return ff2 end 60 chunk = original and chunk
59 ff1 = f1(rf1) 61 elseif chunk then
60 end 62 if index == n then return chunk
61 end 63 else index = index + 1 end
62end 64 else
63]] 65 base.error("filter returned inappropriate nil")
64 66 end
65local function chain2(f1, f2)
66 local co = coroutine.create(function(chunk)
67 while true do
68 local filtered1 = f1(chunk)
69 local filtered2 = f2(filtered1)
70 local done2 = filtered1 and ""
71 while true do
72 if filtered2 == "" or filtered2 == nil then break end
73 coroutine.yield(filtered2)
74 filtered2 = f2(done2)
75 end 67 end
76 if filtered1 == "" then chunk = coroutine.yield(filtered1)
77 elseif filtered1 == nil then return nil
78 else chunk = chunk and "" end
79 end 68 end
80 end)
81 return function(chunk)
82 local _, res = coroutine.resume(co, chunk)
83 return res
84 end 69 end
85end 70end
86 71
87-- chains a bunch of filters together
88function filter.chain(...)
89 local f = arg[1]
90 for i = 2, table.getn(arg) do
91 f = chain2(f, arg[i])
92 end
93 return f
94end
95
96----------------------------------------------------------------------------- 72-----------------------------------------------------------------------------
97-- Source stuff 73-- Source stuff
98----------------------------------------------------------------------------- 74-----------------------------------------------------------------------------
@@ -165,23 +141,28 @@ end
165-- chains a source with a filter 141-- chains a source with a filter
166function source.chain(src, f) 142function source.chain(src, f)
167 base.assert(src and f) 143 base.assert(src and f)
168 local co = coroutine.create(function() 144 local last_in, last_out = "", ""
169 while true do 145 return function()
170 local chunk, err = src() 146 if last_out == "" then
171 if err then return nil, err end
172 local filtered = f(chunk)
173 local done = chunk and ""
174 while true do 147 while true do
175 coroutine.yield(filtered) 148 local err
176 if filtered == done then break end 149 last_in, err = src()
177 filtered = f(done) 150 if err then return nil, err end
151 last_out = f(last_in)
152 if last_out ~= "" then return last_out end
153 if not last_in then
154 error('filter returned inappropriate ""')
155 end
178 end 156 end
157 elseif last_out then
158 last_out = f(last_in and "")
159 if last_in and not last_out then
160 error('filter returned inappropriate nil')
161 end
162 return last_out
163 else
164 base.error("source is empty", 2)
179 end 165 end
180 end)
181 return function()
182 local ret, a, b = coroutine.resume(co)
183 if ret then return a, b
184 else return nil, a end
185 end 166 end
186end 167end
187 168
@@ -260,14 +241,16 @@ end
260function sink.chain(f, snk) 241function sink.chain(f, snk)
261 base.assert(f and snk) 242 base.assert(f and snk)
262 return function(chunk, err) 243 return function(chunk, err)
263 local filtered = f(chunk) 244 if chunk ~= "" then
264 local done = chunk and "" 245 local filtered = f(chunk)
265 while true do 246 local done = chunk and ""
266 local ret, snkerr = snk(filtered, err) 247 while true do
267 if not ret then return nil, snkerr end 248 local ret, snkerr = snk(filtered, err)
268 if filtered == done then return 1 end 249 if not ret then return nil, snkerr end
269 filtered = f(done) 250 if filtered == done then return 1 end
270 end 251 filtered = f(done)
252 end
253 else return 1 end
271 end 254 end
272end 255end
273 256
diff --git a/src/wsocket.c b/src/wsocket.c
index 0294dce..69fac4d 100644
--- a/src/wsocket.c
+++ b/src/wsocket.c
@@ -193,7 +193,7 @@ int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, p_tm tm)
193 *sent = 0; 193 *sent = 0;
194 for ( ;; ) { 194 for ( ;; ) {
195 /* try to send something */ 195 /* try to send something */
196 int put = send(*ps, data, count, 0); 196 int put = send(*ps, data, (int) count, 0);
197 /* if we sent something, we are done */ 197 /* if we sent something, we are done */
198 if (put > 0) { 198 if (put > 0) {
199 *sent = put; 199 *sent = put;
diff --git a/test/ltn12test.lua b/test/ltn12test.lua
new file mode 100644
index 0000000..7922bf1
--- /dev/null
+++ b/test/ltn12test.lua
@@ -0,0 +1,275 @@
1local ltn12 = require("ltn12")
2
3dofile("testsupport.lua")
4
5local function format(chunk)
6 if chunk then
7 if chunk == "" then return "''"
8 else return string.len(chunk) end
9 else return "nil" end
10end
11
12local function show(name, input, output)
13 local sin = format(input)
14 local sout = format(output)
15 io.write(name, ": ", sin, " -> ", sout, "\n")
16end
17
18local function chunked(length)
19 local tmp
20 return function(chunk)
21 local ret
22 if chunk and chunk ~= "" then
23 tmp = chunk
24 end
25 ret = string.sub(tmp, 1, length)
26 tmp = string.sub(tmp, length+1)
27 if not chunk and ret == "" then ret = nil end
28 return ret
29 end
30end
31
32local function named(f, name)
33 return function(chunk)
34 local ret = f(chunk)
35 show(name, chunk, ret)
36 return ret
37 end
38end
39
40--------------------------------
41local function split(size)
42 local buffer = ""
43 local last_out = ""
44 local last_in = ""
45 local function output(chunk)
46 local part = string.sub(buffer, 1, size)
47 buffer = string.sub(buffer, size+1)
48 last_out = (part ~= "" or chunk) and part
49 last_in = chunk
50 return last_out
51 end
52 return function(chunk, done)
53 if done then
54 return not last_in and not last_out
55 end
56 -- check if argument is consistent with state
57 if not chunk then
58 if last_in and last_in ~= "" and last_out ~= "" then
59 error("nil chunk following data chunk", 2)
60 end
61 if not last_out then error("extra nil chunk", 2) end
62 return output(chunk)
63 elseif chunk == "" then
64 if last_out == "" then error('extra "" chunk', 2) end
65 if not last_out then error('"" chunk following nil return', 2) end
66 if not last_in then error('"" chunk following nil chunk', 2) end
67 return output(chunk)
68 else
69 if not last_in then error("data chunk following nil chunk", 2) end
70 if last_in ~= "" and last_out ~= "" then
71 error("data chunk following data chunk", 2)
72 end
73 buffer = chunk
74 return output(chunk)
75 end
76 end
77end
78
79--------------------------------
80local function format(chunk)
81 if chunk then
82 if chunk == "" then return "''"
83 else return string.len(chunk) end
84 else return "nil" end
85end
86
87--------------------------------
88local function merge(size)
89 local buffer = ""
90 local last_out = ""
91 local last_in = ""
92 local function output(chunk)
93 local part
94 if string.len(buffer) >= size or not chunk then
95 part = buffer
96 buffer = ""
97 else
98 part = ""
99 end
100 last_out = (part ~= "" or chunk) and part
101 last_in = chunk
102 return last_out
103 end
104 return function(chunk, done)
105 if done then
106 return not last_in and not last_out
107 end
108 -- check if argument is consistent with state
109 if not chunk then
110 if last_in and last_in ~= "" and last_out ~= "" then
111 error("nil chunk following data chunk", 2)
112 end
113 if not last_out then error("extra nil chunk", 2) end
114 return output(chunk)
115 elseif chunk == "" then
116 if last_out == "" then error('extra "" chunk', 2) end
117 if not last_out then error('"" chunk following nil return', 2) end
118 if not last_in then error('"" chunk following nil chunk', 2) end
119 return output(chunk)
120 else
121 if not last_in then error("data chunk following nil chunk", 2) end
122 if last_in ~= "" and last_out ~= "" then
123 error("data chunk following data chunk", 2)
124 end
125 buffer = buffer .. chunk
126 return output(chunk)
127 end
128 end
129end
130
131--------------------------------
132io.write("testing sink.table: ")
133local sink, t = ltn12.sink.table()
134local s, c = "", ""
135for i = 0, 10 do
136 c = string.rep(string.char(i), i)
137 s = s .. c
138 assert(sink(c), "returned error")
139end
140assert(sink(nil), "returned error")
141assert(table.concat(t) == s, "mismatch")
142print("ok")
143
144--------------------------------
145io.write("testing sink.chain (with split): ")
146sink, t = ltn12.sink.table()
147local filter = split(3)
148sink = ltn12.sink.chain(filter, sink)
149s = "123456789012345678901234567890"
150assert(sink(s), "returned error")
151assert(sink(s), "returned error")
152assert(sink(nil), "returned error")
153assert(table.concat(t) == s .. s, "mismatch")
154assert(filter(nil, 1), "filter not empty")
155print("ok")
156
157--------------------------------
158io.write("testing sink.chain (with merge): ")
159sink, t = ltn12.sink.table()
160filter = merge(10)
161sink = ltn12.sink.chain(filter, sink)
162s = string.rep("123", 30)
163s = s .. string.rep("4321", 30)
164for i = 1, 30 do
165 assert(sink("123"), "returned error")
166end
167for i = 1, 30 do
168 assert(sink("4321"), "returned error")
169end
170assert(sink(nil), "returned error")
171assert(filter(nil, 1), "filter not empty")
172assert(table.concat(t) == s, "mismatch")
173print("ok")
174
175--------------------------------
176io.write("testing source.string and pump.all: ")
177local source = ltn12.source.string(s)
178sink, t = ltn12.sink.table()
179assert(ltn12.pump.all(source, sink), "returned error")
180assert(table.concat(t) == s, "mismatch")
181print("ok")
182
183--------------------------------
184io.write("testing source.chain (with split): ")
185source = ltn12.source.string(s)
186filter = split(5)
187source = ltn12.source.chain(source, filter)
188sink, t = ltn12.sink.table()
189assert(ltn12.pump.all(source, sink), "returned error")
190assert(table.concat(t) == s, "mismatch")
191assert(filter(nil, 1), "filter not empty")
192print("ok")
193
194--------------------------------
195io.write("testing source.chain (with split) and sink.chain (with merge): ")
196source = ltn12.source.string(s)
197filter = split(5)
198source = ltn12.source.chain(source, filter)
199local filter2 = merge(13)
200sink, t = ltn12.sink.table()
201sink = ltn12.sink.chain(filter2, sink)
202assert(ltn12.pump.all(source, sink), "returned error")
203assert(table.concat(t) == s, "mismatch")
204assert(filter(nil, 1), "filter not empty")
205assert(filter2(nil, 1), "filter2 not empty")
206print("ok")
207
208--------------------------------
209io.write("testing filter.chain (and sink.chain, with split, merge): ")
210source = ltn12.source.string(s)
211filter = split(5)
212filter2 = merge(13)
213local chain = ltn12.filter.chain(filter, filter2)
214sink, t = ltn12.sink.table()
215sink = ltn12.sink.chain(chain, sink)
216assert(ltn12.pump.all(source, sink), "returned error")
217assert(table.concat(t) == s, "mismatch")
218assert(filter(nil, 1), "filter not empty")
219assert(filter2(nil, 1), "filter2 not empty")
220print("ok")
221
222--------------------------------
223io.write("testing filter.chain (and sink.chain, a bunch): ")
224source = ltn12.source.string(s)
225filter = split(5)
226filter2 = merge(13)
227local filter3 = split(7)
228local filter4 = merge(11)
229local filter5 = split(10)
230chain = ltn12.filter.chain(filter, filter2, filter3, filter4, filter5)
231sink, t = ltn12.sink.table()
232sink = ltn12.sink.chain(chain, sink)
233assert(ltn12.pump.all(source, sink))
234assert(table.concat(t) == s, "mismatch")
235assert(filter(nil, 1), "filter not empty")
236assert(filter2(nil, 1), "filter2 not empty")
237assert(filter3(nil, 1), "filter3 not empty")
238assert(filter4(nil, 1), "filter4 not empty")
239assert(filter5(nil, 1), "filter5 not empty")
240print("ok")
241
242--------------------------------
243io.write("testing filter.chain (and source.chain, with split, merge): ")
244source = ltn12.source.string(s)
245filter = split(5)
246filter2 = merge(13)
247local chain = ltn12.filter.chain(filter, filter2)
248sink, t = ltn12.sink.table()
249source = ltn12.source.chain(source, chain)
250assert(ltn12.pump.all(source, sink), "returned error")
251assert(table.concat(t) == s, "mismatch")
252assert(filter(nil, 1), "filter not empty")
253assert(filter2(nil, 1), "filter2 not empty")
254print("ok")
255
256--------------------------------
257io.write("testing filter.chain (and source.chain, a bunch): ")
258source = ltn12.source.string(s)
259filter = split(5)
260filter2 = merge(13)
261local filter3 = split(7)
262local filter4 = merge(11)
263local filter5 = split(10)
264chain = ltn12.filter.chain(filter, filter2, filter3, filter4, filter5)
265sink, t = ltn12.sink.table()
266source = ltn12.source.chain(source, chain)
267assert(ltn12.pump.all(source, sink))
268assert(table.concat(t) == s, "mismatch")
269assert(filter(nil, 1), "filter not empty")
270assert(filter2(nil, 1), "filter2 not empty")
271assert(filter3(nil, 1), "filter3 not empty")
272assert(filter4(nil, 1), "filter4 not empty")
273assert(filter5(nil, 1), "filter5 not empty")
274print("ok")
275
diff --git a/test/mimetest.lua b/test/mimetest.lua
index 834d99f..2f6b7a8 100644
--- a/test/mimetest.lua
+++ b/test/mimetest.lua
@@ -47,42 +47,6 @@ local function random(handle, io_err)
47 else return ltn12.source.empty(io_err or "unable to open file") end 47 else return ltn12.source.empty(io_err or "unable to open file") end
48end 48end
49 49
50local function format(chunk)
51 if chunk then
52 if chunk == "" then return "''"
53 else return string.len(chunk) end
54 else return "nil" end
55end
56
57local function show(name, input, output)
58 local sin = format(input)
59 local sout = format(output)
60 io.write(name, ": ", sin, " -> ", sout, "\n")
61end
62
63local function chunked(length)
64 local tmp
65 return function(chunk)
66 local ret
67 if chunk and chunk ~= "" then
68 tmp = chunk
69 end
70 ret = string.sub(tmp, 1, length)
71 tmp = string.sub(tmp, length+1)
72 if not chunk and ret == "" then ret = nil end
73 return ret
74 end
75end
76
77--[[
78local function named(f, name)
79 return function(chunk)
80 local ret = f(chunk)
81 show(name, chunk, ret)
82 return ret
83 end
84end
85]]
86 50
87local function named(f) 51local function named(f)
88 return f 52 return f