Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/stevedonovan/Penlight.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsteve donovan <steve.j.donovan@gmail.com>2011-10-02 20:37:57 +0400
committersteve donovan <steve.j.donovan@gmail.com>2011-10-02 20:37:57 +0400
commit6a1685ab637dcb7fbf8632b6359d389e7e30d080 (patch)
tree85c5c0ab666c3a1ed825d40347c6073b975b9ca4
parent3072c1d98beafc3834d4ddb6fe28c0e9fbbd6748 (diff)
update tests: new test for derived classes from List
-rw-r--r--tests/test-args.lua2
-rw-r--r--tests/test-data.lua330
-rw-r--r--tests/test-vector.lua115
3 files changed, 282 insertions, 165 deletions
diff --git a/tests/test-args.lua b/tests/test-args.lua
index 53b24c2..56418eb 100644
--- a/tests/test-args.lua
+++ b/tests/test-args.lua
@@ -20,6 +20,8 @@ flags,args = parse_args({'-k','-b=23','-o','hello','--out'},{o=true})
asserteq(flags,{out=true,o="hello",k=true,b="23"})
+do return end
+
-- modify this script's module path so it looks in the 'lua' subdirectory
-- for its modules
app.require_here 'lua'
diff --git a/tests/test-data.lua b/tests/test-data.lua
index fe11b79..cce15e1 100644
--- a/tests/test-data.lua
+++ b/tests/test-data.lua
@@ -1,165 +1,165 @@
---_DEBUG=true
-data = require 'pl.data'
-List = require 'pl.List'
-array = require 'pl.array2d'
-seq = require 'pl.seq'
-utils = require 'pl.utils'
-stringio = require 'pl.stringio'
-open = stringio. open
-asserteq = require 'pl.test' . asserteq
-T = require 'pl.test'. tuple
-
--- tab-separated data, explicit column names
-t1f = open [[
-EventID Magnitude LocationX LocationY LocationZ LocationError EventDate DataFile
-981124001 2.0 18988.4 10047.1 4149.7 33.8 24/11/1998 11:18:05 981124DF.AAB
-981125001 0.8 19104.0 9970.4 5088.7 3.0 25/11/1998 05:44:54 981125DF.AAB
-981127003 0.5 19012.5 9946.9 3831.2 46.0 27/11/1998 17:15:17 981127DF.AAD
-981127005 0.6 18676.4 10606.2 3761.9 4.4 27/11/1998 17:46:36 981127DF.AAF
-981127006 0.2 19109.9 9716.5 3612.0 11.8 27/11/1998 19:29:51 981127DF.AAG
-]]
-
-t1 = data.read (t1f)
--- column_by_name returns a List
-asserteq(t1:column_by_name 'Magnitude',List{2,0.8,0.5,0.6,0.2})
--- can use array.column as well
-asserteq(array.column(t1,2),{2,0.8,0.5,0.6,0.2})
-
--- only numerical columns (deduced from first data row) are converted by default
--- can look up indices in the list fieldnames.
-EDI = t1.fieldnames:index 'EventDate'
-assert(type(t1[1][EDI]) == 'string')
-
--- select method returns a sequence, in this case single-valued.
--- (Note that seq.copy returns a List)
-asserteq(seq(t1:select 'LocationX where Magnitude > 0.5'):copy(),List{18988.4,19104,18676.4})
-
---[[
---a common select usage pattern:
-for event,mag in t1:select 'EventID,Magnitude sort by Magnitude desc' do
- print(event,mag)
-end
---]]
-
--- space-separated, but with last field containing spaces.
-t2f = open [[
-USER PID %MEM %CPU COMMAND
-sdonovan 2333 0.3 0.1 background --n=2
-root 2332 0.4 0.2 fred --start=yes
-root 2338 0.2 0.1 backyard-process
-]]
-
-t2,err = data.read(t2f,{last_field_collect=true})
-if not t2 then return print (err) end
-
--- the last_field_collect option is useful with space-delimited data where the last
--- field may contain spaces. Otherwise, a record count mismatch should be an error!
-lt2 = List(t2[2])
-asserteq(lt2:join ',','root,2332,0.4,0.2,fred --start=yes')
-
--- fieldnames are converted into valid identifiers by substituting _
--- (we do this to make select queries parseable by Lua)
-asserteq(t2.fieldnames,List{'USER','PID','_MEM','_CPU','COMMAND'})
-
--- select queries are NOT SQL so remember to use == ! (and no 'between' operator, sorry)
---s,err = t2:select('_MEM where USER="root"')
---assert(err == [[[string "tmp"]:9: unexpected symbol near '=']])
-
-s = t2:select('_MEM where USER=="root"')
-assert(s() == 0.4)
-assert(s() == 0.2)
-assert(s() == nil)
-
--- CSV, Excel style
-t3f = open [[
-Department Name,Employee ID,Project,Hours Booked
-sales,1231,overhead,4
-sales,1255,overhead,3
-engineering,1501,development,5
-engineering,1501,maintenance,3
-engineering,1433,maintenance,10
-]]
-
-t3 = data.read(t3f)
-
--- a common operation is to select using a given list of columns, and each row
--- on some explicit condition. The select() method can take a table with these
--- parameters
-keepcols = {'Employee_ID','Hours_Booked'}
-
-q = t3:select { fields = keepcols,
- where = function(row) return row[1]=='engineering' end
- }
-
-asserteq(seq.copy2(q),{{1501,5},{1501,3},{1433,10}})
-
--- another pattern is doing a select to restrict rows & columns, process some
--- fields and write out the modified rows.
-
-utils.import 'pl.func'
-
-outf = stringio.create()
-
-names = {[1501]='don',[1433]='dilbert'}
-
-t3:write_row (outf,{'Employee','Hours_Booked'})
-q = t3:select_row {fields=keepcols,where=Eq(_1[1],'engineering')}
-for row in q do
- row[1] = names[row[1]]
- t3:write_row(outf,row)
-end
-
-asserteq(outf:value(),
-[[
-Employee,Hours_Booked
-don,5
-don,3
-dilbert,10
-]])
-
--- data may not always have column headers. When creating a data object
--- from a two-dimensional array, must specify the fieldnames, as a list or a string.
--- The delimiter is deduced from the fieldname string, so a string just containing
--- the delimiter will set it, and the fieldnames will be empty.
-local dat = List()
-local row = List.range(1,10)
-for i = 1,10 do
- dat:append(row:map('*',i))
-end
-dat = data.new(dat,',')
-local out = stringio.create()
-dat:write(out,',')
-asserteq(out:value(), [[
-1,2,3,4,5,6,7,8,9,10
-2,4,6,8,10,12,14,16,18,20
-3,6,9,12,15,18,21,24,27,30
-4,8,12,16,20,24,28,32,36,40
-5,10,15,20,25,30,35,40,45,50
-6,12,18,24,30,36,42,48,54,60
-7,14,21,28,35,42,49,56,63,70
-8,16,24,32,40,48,56,64,72,80
-9,18,27,36,45,54,63,72,81,90
-10,20,30,40,50,60,70,80,90,100
-]])
-
--- you can always use numerical field indices, AWK-style;
--- note how the copy_select method gives you a data object instead of an
--- iterator over the fields
-local res = dat:copy_select '$1,$3 where $1 > 5'
-local L = List
-asserteq(L(res),L{
- L{6, 18},
- L{7, 21},
- L{8, 24},
- L{9, 27},
- L{10,30},
-})
-
--- the column_by_name method may take a fieldname or an index
-asserteq(dat:column_by_name(2), L{2,4,6,8,10,12,14,16,18,20})
-
--- the field list may contain expressions or even constants
-local q = dat:select '$3,2*$4 where $1 == 8'
-asserteq(T(q()),T(24,64))
-
-
+--_DEBUG=true
+data = require 'pl.data'
+List = require 'pl.List'
+array = require 'pl.array2d'
+seq = require 'pl.seq'
+utils = require 'pl.utils'
+stringio = require 'pl.stringio'
+open = stringio. open
+asserteq = require 'pl.test' . asserteq
+T = require 'pl.test'. tuple
+
+-- tab-separated data, explicit column names
+t1f = open [[
+EventID Magnitude LocationX LocationY LocationZ LocationError EventDate DataFile
+981124001 2.0 18988.4 10047.1 4149.7 33.8 24/11/1998 11:18:05 981124DF.AAB
+981125001 0.8 19104.0 9970.4 5088.7 3.0 25/11/1998 05:44:54 981125DF.AAB
+981127003 0.5 19012.5 9946.9 3831.2 46.0 27/11/1998 17:15:17 981127DF.AAD
+981127005 0.6 18676.4 10606.2 3761.9 4.4 27/11/1998 17:46:36 981127DF.AAF
+981127006 0.2 19109.9 9716.5 3612.0 11.8 27/11/1998 19:29:51 981127DF.AAG
+]]
+
+t1 = data.read (t1f)
+-- column_by_name returns a List
+asserteq(t1:column_by_name 'Magnitude',List{2,0.8,0.5,0.6,0.2})
+-- can use array.column as well
+asserteq(array.column(t1,2),{2,0.8,0.5,0.6,0.2})
+
+-- only numerical columns (deduced from first data row) are converted by default
+-- can look up indices in the list fieldnames.
+EDI = t1.fieldnames:index 'EventDate'
+assert(type(t1[1][EDI]) == 'string')
+
+-- select method returns a sequence, in this case single-valued.
+-- (Note that seq.copy returns a List)
+asserteq(seq(t1:select 'LocationX where Magnitude > 0.5'):copy(),List{18988.4,19104,18676.4})
+
+--[[
+--a common select usage pattern:
+for event,mag in t1:select 'EventID,Magnitude sort by Magnitude desc' do
+ print(event,mag)
+end
+--]]
+
+-- space-separated, but with last field containing spaces.
+t2f = open [[
+USER PID %MEM %CPU COMMAND
+sdonovan 2333 0.3 0.1 background --n=2
+root 2332 0.4 0.2 fred --start=yes
+root 2338 0.2 0.1 backyard-process
+]]
+
+t2,err = data.read(t2f,{last_field_collect=true})
+if not t2 then return print (err) end
+
+-- the last_field_collect option is useful with space-delimited data where the last
+-- field may contain spaces. Otherwise, a record count mismatch should be an error!
+lt2 = List(t2[2])
+asserteq(lt2:join ',','root,2332,0.4,0.2,fred --start=yes')
+
+-- fieldnames are converted into valid identifiers by substituting _
+-- (we do this to make select queries parseable by Lua)
+asserteq(t2.fieldnames,List{'USER','PID','_MEM','_CPU','COMMAND'})
+
+-- select queries are NOT SQL so remember to use == ! (and no 'between' operator, sorry)
+--s,err = t2:select('_MEM where USER="root"')
+--assert(err == [[[string "tmp"]:9: unexpected symbol near '=']])
+
+s = t2:select('_MEM where USER=="root"')
+assert(s() == 0.4)
+assert(s() == 0.2)
+assert(s() == nil)
+
+-- CSV, Excel style
+t3f = open [[
+Department Name,Employee ID,Project,Hours Booked
+sales,1231,overhead,4
+sales,1255,overhead,3
+engineering,1501,development,5
+engineering,1501,maintenance,3
+engineering,1433,maintenance,10
+]]
+
+t3 = data.read(t3f)
+
+-- a common operation is to select using a given list of columns, and each row
+-- on some explicit condition. The select() method can take a table with these
+-- parameters
+keepcols = {'Employee_ID','Hours_Booked'}
+
+q = t3:select { fields = keepcols,
+ where = function(row) return row[1]=='engineering' end
+ }
+
+asserteq(seq.copy2(q),{{1501,5},{1501,3},{1433,10}})
+
+-- another pattern is doing a select to restrict rows & columns, process some
+-- fields and write out the modified rows.
+
+utils.import 'pl.func'
+
+outf = stringio.create()
+
+names = {[1501]='don',[1433]='dilbert'}
+
+t3:write_row (outf,{'Employee','Hours_Booked'})
+q = t3:select_row {fields=keepcols,where=Eq(_1[1],'engineering')}
+for row in q do
+ row[1] = names[row[1]]
+ t3:write_row(outf,row)
+end
+
+asserteq(outf:value(),
+[[
+Employee,Hours_Booked
+don,5
+don,3
+dilbert,10
+]])
+
+-- data may not always have column headers. When creating a data object
+-- from a two-dimensional array, must specify the fieldnames, as a list or a string.
+-- The delimiter is deduced from the fieldname string, so a string just containing
+-- the delimiter will set it, and the fieldnames will be empty.
+local dat = List()
+local row = List.range(1,10)
+for i = 1,10 do
+ dat:append(row:map('*',i))
+end
+dat = data.new(dat,',')
+local out = stringio.create()
+dat:write(out,',')
+asserteq(out:value(), [[
+1,2,3,4,5,6,7,8,9,10
+2,4,6,8,10,12,14,16,18,20
+3,6,9,12,15,18,21,24,27,30
+4,8,12,16,20,24,28,32,36,40
+5,10,15,20,25,30,35,40,45,50
+6,12,18,24,30,36,42,48,54,60
+7,14,21,28,35,42,49,56,63,70
+8,16,24,32,40,48,56,64,72,80
+9,18,27,36,45,54,63,72,81,90
+10,20,30,40,50,60,70,80,90,100
+]])
+
+-- you can always use numerical field indices, AWK-style;
+-- note how the copy_select method gives you a data object instead of an
+-- iterator over the fields
+local res = dat:copy_select '$1,$3 where $1 > 5'
+local L = List
+asserteq(L(res),L{
+ L{6, 18},
+ L{7,21},
+ L{8,24},
+ L{9,27},
+ L{10,30},
+})
+
+-- the column_by_name method may take a fieldname or an index
+asserteq(dat:column_by_name(2), L{2,4,6,8,10,12,14,16,18,20})
+
+-- the field list may contain expressions or even constants
+local q = dat:select '$3,2*$4 where $1 == 8'
+asserteq(T(q()),T(24,64))
+
+
diff --git a/tests/test-vector.lua b/tests/test-vector.lua
new file mode 100644
index 0000000..7f8f0f3
--- /dev/null
+++ b/tests/test-vector.lua
@@ -0,0 +1,115 @@
+---- deriving specialized classes from List
+-- illustrating covariance of List methods
+require 'pl'
+local L = utils.string_lambda
+local asserteq = test.asserteq
+
+class.Vector(List)
+
+
+function Vector.range (x1,x2,delta)
+ return Vector(List.range(x1,x2,delta))
+end
+
+local function vbinop (op,v1,v2,scalar)
+ if not Vector:class_of(v1) then
+ v2, v1 = v1, v2
+ end
+ if type(v2) ~= 'table' then
+ return v1:map(op,v2)
+ else
+ if scalar then error("operation not permitted on two vectors",3) end
+ if #v1 ~= #v2 then error("vectors have different lengths",3) end
+ return v1:map2(op,v2)
+ end
+end
+
+function Vector.__add (v1,v2)
+ return vbinop(operator.add,v1,v2)
+end
+
+function Vector.__sub (v1,v2)
+ return vbinop(operator.sub,v1,v2)
+end
+
+function Vector.__mul (v1,v2)
+ return vbinop(operator.mul,v1,v2,true)
+end
+
+function Vector.__div (v1,v2)
+ return vbinop(operator.div,v1,v2,true)
+end
+
+function Vector.__unm (v)
+ return v:map(operator.unm)
+end
+
+Vector.catch(List.default_map_with(math))
+
+v = Vector()
+
+assert(v:is_a(Vector))
+assert(Vector:class_of(v))
+
+v:append(10)
+v:append(20)
+asserteq(1+v,v+1)
+
+-- covariance: the inherited Vector.map returns a Vector
+asserteq(List{1,2} + v:map (L'2*_'),{21,42})
+
+u = Vector{1,2}
+
+asserteq(v + u,{11,22})
+asserteq(v - u,{9,18})
+asserteq (v - 1, {9,19})
+asserteq(2 * v, {20,40})
+-- print(v * v) -- throws error: not permitted
+-- print(v + Vector{1,2,3}) -- throws error: different lengths
+asserteq(2*v + u, {21,42})
+asserteq(-v, {-10,-20})
+
+-- Vector.slice returns the Right Thing due to covariance
+asserteq(
+ Vector.range(0,1,0.1):slice(1,3)+1,
+ {1,1.1,1.2},
+ 1e-8)
+
+u:transform '_+1'
+asserteq(u,{2,3})
+
+u = Vector.range(0,1,0.1)
+asserteq(
+ u:map(math.sin),
+ {0,0.0998,0.1986,0.2955,0.3894,0.4794,0.5646,0.6442,0.7173,0.7833,0.8414},
+0.001)
+
+-- unknown Vector methods are assumed to be math.* functions
+asserteq(Vector{-1,2,3,-4}:abs(),Vector.range(1,4))
+
+local R = Vector.range
+
+-- concatenating two Vectors returns another vector (covariance again)
+-- note the operator precedence here...
+asserteq((
+ R(0,1,0.1)..R(1.2,2,0.2)) + 1,
+ {1,1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,1.9,2,2.2,2.4,2.6,2.8,3},
+ 1e-8)
+
+
+class.Strings(List)
+
+Strings.catch(List.default_map_with(string))
+
+ls = Strings{'one','two','three'}
+asserteq(ls:upper(),{'ONE','TWO','THREE'})
+asserteq(ls:sub(1,2),{'on','tw','th'})
+
+-- an issue with covariance: not all map operations on specialized lists
+-- results in another list of that type!
+local sizes = ls:map '#'
+asserteq(sizes, {3,3,5})
+asserteq(utils.type(sizes),'Strings')
+
+
+