-updated liquidsoap scripts + library to be liquidsoap-beta2 compliant

This commit is contained in:
martin 2011-07-06 11:14:51 -04:00
parent 022b013dd2
commit 3dc1380fab
24 changed files with 593 additions and 192 deletions

View file

@ -0,0 +1,21 @@
# This is the test for bug #403 from our old trac.
#
# Make a switch() declare itself ready and arrange to use it for the next
# frame where it isn't ready anymore.
#
# Two switches A and B
# A is only ready for a short period of time due to its predicates.
# B reselects at the end of a frame just before A becomes unavailable
# as a result, B has selected = A, attempts to stream it
# but A finds itself not ready anymore.
# In other words, B committed but A did not.
r = ref false
pred = { v=!r ; r:=false ; v }
add_timeout(2.,{ r := true ; (-1.) })
mixer = fallback(id="mixer", track_sensitive=false,
[at(pred, sine(duration=3.)), blank()])
output.dummy(mixer)
add_timeout(3.,{ print("TEST PASSED") ; shutdown() ; (-1.) })

View file

@ -0,0 +1,10 @@
# In LS-268 we realized that an incorrect assumption had
# been made in code from LS-394, resulting in a crash in
# case of source re-awakening.
p = input.http("http://localhost:8000/nonexistent")
o = output.dummy(fallible=true,p)
add_timeout(2.,{ source.shutdown(o) ; (-1.) })
add_timeout(3.,{ output.dummy(fallible=true,p) ; (-1.) })
add_timeout(4.,{ shutdown() ; (-1.) })

View file

@ -0,0 +1,11 @@
s = on_track(
fun(_)-> begin print("TEST PASSED") shutdown() end,
blank(duration=1.))
r = ref false
d = source.dynamic({ if !r then [s] else [] end })
output.dummy(mksafe(d))
add_timeout(2.,{r:=true;(-1.)})
add_timeout(4.,{print("TEST FAILED");shutdown();(-1.)})

View file

@ -0,0 +1,15 @@
s1 = fail()
s2 = on_track(
fun(_)-> begin print("TEST PASSED") shutdown() end,
blank(duration=1.))
r = ref 0
d = source.dynamic({ if !r==1 then [s1]
elsif !r==2 then [s2]
else [] end })
output.dummy(mksafe(d))
add_timeout(2.,{r:=1;(-1.)})
add_timeout(3.,{r:=2;(-1.)})
add_timeout(5.,{print("TEST FAILED");shutdown();(-1.)})

View file

@ -0,0 +1,17 @@
# Scenario:
# Let foo start using q, then stop it, skip in q.
# When foo restarts it doesn't know that q isn't ready anymore,
# which can lead to a crash.
q = once(sine(duration=10.))
output.dummy(id="bar",mksafe(q))
output.dummy(id="foo",fallback([amplify(1.,q),blank(duration=1.)]))
def at(t,s)
add_timeout(t,{ignore(server.execute(s));(-1.)})
end
at(3.,"foo.stop")
at(4.,"bar.skip")
at(5.,"foo.start")
add_timeout(6.,{print("TEST PASSED");shutdown();(-1.)})

View file

@ -0,0 +1,13 @@
# In LS-503 we realized that a source may throw an
# exception during output_get_ready call in the initial
# main phase. This code reproduces the issue by throwing
# an exception in output.icecast.
# Reopen stderr to /dev/null to
# disable printing expected exception
reopen.stderr("/dev/null")
p = input.http("http://localhost:8000/nonexistent")
o = output.icecast(%wav,fallible=true,host="nonexistent",
mount="test",p)

View file

@ -0,0 +1,16 @@
DISTFILES = Makefile $(wildcard *.liq) $(wildcard *.pl)
top_srcdir = ../..
include $(top_srcdir)/Makefile.rules
test:
@for i in $(wildcard *.liq) ; do \
echo -n "$$i... " ; $(top_srcdir)/src/liquidsoap -q - < ./$$i | head -n 1 ; \
done
@echo -n "type_errors.pl... " ; \
if (./type_errors.pl > /dev/null 2> /dev/null) ; then \
echo "TEST PASSED (check manually the prettiness of messages)" ; \
else \
echo "TEST FAILED" ; \
fi

View file

@ -0,0 +1,43 @@
count = ref 1
fail = ref false
def echo(s)
# system("echo "^quote(s))
if s != string_of(!count) then
fail := true
end
count := !count + 1
()
end
def test(lbl,f)
if f() then echo(lbl) else echo("fail "^lbl) end
end
test("1",{ 1==1 })
test("2",{ 1+1==2 })
test("3",{ (-1)+2==1 })
test("4",{ (-1)+2 <= 3*2 })
test("5",{ true })
test("6",{ true and true })
test("7",{ 1==1 and 1==1 })
test("8",{ (1==1) and (1==1) })
test("9",{ true and (-1)+2 <= 3*2 })
l = [ ("bla",""), ("bli","x"), ("blo","xx"), ("blu","xxx"), ("dix","10") ]
echo(l["dix"])
test("11",{ 2 == list.length(string.split(separator="",l["blo"])) })
%ifdef foobarbaz
if = if is not a well-formed expression, and we do not care...
%endif
echo("1#{1+1}")
echo(string_of(int_of_float(float_of_string(default=13.,"blah"))))
f=fun(x)->x
# Checking that the following is not recursive:
f=fun(x)->f(x)
echo(string_of(f(14)))
if !fail then print("TEST FAILED") else print("TEST PASSED") end

View file

@ -0,0 +1,82 @@
#!/usr/bin/perl -w
use strict ;
my $liquidsoap = "../../src/liquidsoap";
die unless -f $liquidsoap ;
$liquidsoap = "$liquidsoap -c";
sub section {
print "\n*** $_[0] ***\n\n" ;
}
sub incorrect {
my $expr = pop ;
print "Incorrect expression $expr...\n" ;
system "$liquidsoap '$expr'" ;
die unless (($?>>8)==1) ;
print "\n" ;
}
sub correct {
my $expr = pop ;
print "Correct expression $expr...\n" ;
system "$liquidsoap -i '$expr'" ;
die unless (($?>>8)==0) ;
print "\n";
}
section("BASIC");
incorrect('[1]==["1"]');
incorrect('1==["1"]');
incorrect('1==(1,"1")');
# In some of those examples the type error could be reported for a
# sub-expression since we have location information.
# With the concise error, it's still pretty good currently.
incorrect('(1,1)==(1,"1")');
incorrect('(1,1)==("1",1)');
incorrect('1==request.create("")');
incorrect('fun(x)->x(snd(x))');
section("SUBTYPING");
incorrect('(1:unit)');
correct('((blank():source(1,1,1)):source(*,*,*))');
incorrect('((blank():source(*,*,*)):source(1,1,1))');
# Next one requires the inference of a subtype (fixed vs. variable arity)
correct('audio_to_stereo(add([]))');
section("CONSTRAINTS");
incorrect('"bl"+"a"');
incorrect('(fun(a,b)->a+b)==(fun(a,b)->a+b)');
incorrect('fun(x)->x(x)'); # TODO is it an accident that we get same varname
incorrect('def f(x) y=snd(x) y(x) end');
section("LET GENERALIZATION");
correct('def f(x) = y=x ; y end f(3)+snd(f((1,2)))');
incorrect('def f(x) = y=x ; y end f(3)+"3"');
section("ARGUMENTS");
# The errors should be about the type of the param, not of the function.
incorrect('1+"1"');
# Also, a special simple error is expected for obvious labelling mistakes.
incorrect('fallback(transitions=[],xxxxxxxxxxx=[])');
incorrect('fallback(transitions=[],transitions=[])');
section("FUNCTIONS");
incorrect('fallback(transitions=[fun(~l)->1])');
incorrect('fallback(transitions=[fun(~l=1)->1])');
incorrect('fallback(transitions=[fun(x,y=blank())->y])');
incorrect('fallback(transitions=[fun(x,y)->0])');
correct('f=fallback(transitions=[fun(x,y,a=2)->x])');
incorrect('fallback(transitions=[fun(x,y)->y+1])');
correct('x=fun(f)->f(3) y=x(fun(f,u="1")->u)');
section("CONTENT KIND");
incorrect('output.file(%vorbis(stereo),"foo",mean(blank()))');
incorrect('output.file(%vorbis(stereo),"foo",video.add_image(blank()))');
incorrect('def f(x) = output.file(%vorbis(stereo),"",x) output.file(%vorbis(mono),"",x) end');
incorrect('add([output.file(%vorbis(stereo),"",blank()),output.file(%vorbis(mono),"",blank())])');
incorrect('add([mean(blank()),audio_to_stereo(add([]))])');
print "Everything's good!\n" ;

View file

@ -0,0 +1,112 @@
# Check these examples with: liquidsoap --no-libs -i -c typing.liq
# TODO Throughout this file, parsing locations displayed in error messages
# are often much too inaccurate.
# Check that some polymorphism is allowed.
# id : (string,'a)->'a
def id(a,b)
log(a)
b
end
ignore("bla"==id("bla","bla"))
ignore(0==id("zero",0))
# Reporting locations for the next error is non-trivial, because it is about
# an instantiation of the type of id. The deep error doesn't have relevant
# information about why the int should be a string, the outer one has.
# id(0,0)
# Polymorphism is limited to outer generalizations, this is not system F.
# apply : ((string)->'a)->'a
def apply(f)
f("bla")
# f is not polymorphic, the following is forbidden:
# f(0)
# f(f)
end
# The level checks forbid abusive generalization.
# id' : ('a)->'a
def id'(x)
# If one isn't careful about levels/scoping, f2 gets the type ('a)->'b
# and so does twisted_id.
def f2(y)
x
end
f2(x)
end
# More errors...
# 0=="0"
# [3,""]
# Subtyping, functions and lists.
f1 = fun () -> 3
f2 = fun (a=1) -> a
# This is OK, l1 is a list of elements of type f1.
l1 = [f1,f2]
list.iter(fun (f) -> log(string_of(f())), l1)
# Forbidden. Indeed, f1 doesn't accept any argument -- although f2 does.
# Here the error message may even be too detailed since it goes back to the
# definition of l1 and requires that f1 has type (int)->int.
# list.iter(fun (f) -> log(string_of(f(42))), l1)
# Actually, this is forbidden too, but the reason is more complex...
# The infered type for the function is ((int)->int)->unit,
# and (int)->int is not a subtype of (?int)->int.
# There's no most general answer here since (?int)->int is not a
# subtype of (int)->int either.
# list.iter(fun (f) -> log(string_of(f(42))), [f2])
# Unlike l1, this is not OK, since we don't leave open subtyping constraints
# while infering types.
# I hope we can make the inference smarter in the future, without obfuscating
# the error messages too much.
# The type error here shows the use of all the displayed positions:
# f1 has type t1, f2 has type t2, t1 should be <: t2
# l2 = [ f2, f1 ]
# An error where contravariance flips the roles of both sides..
# [fun (x) -> x+1, fun (y) -> y^"."]
# An error without much locations..
# TODO An explaination about the missing label would help a lot here.
# def f(f)
# f(output.icecast.vorbis)
# f(output.icecast.mp3)
# end
# This causes an occur-check error.
# TODO The printing of the types breaks the sharing of one EVAR
# across two types. Here the sharing is actually the origin of the occur-check
# error. And it's not easy to understand..
# omega = fun (x) -> x(x)
# Now let's test ad-hoc polymorphism.
echo = fun(x) -> system("echo #{quote(string_of(x))}")
ignore("bla")
ignore((1,3.12))
ignore(1 + 1)
ignore(1. + 2.14)
# string is not a Num
# echo("bl"+"a")
ignore(1 <= 2)
ignore((1,2) == (1,3))
# float <> int
# echo(1 == 2.)
# source is not an Ord
# echo(blank()==blank())
def sum_eq(a,b)
a+b == a
end
print("TEST PASSED")