metasploit-framework/lib/metasm/tests/preprocessor.rb

249 lines
5.1 KiB
Ruby

# This file is part of Metasm, the Ruby assembly manipulation suite
# Copyright (C) 2007 Yoann GUILLOT
#
# Licence is LGPL, see LICENCE in the top-level directory
require 'test/unit'
require 'metasm/preprocessor'
# BEWARE OF TEH RUBY PARSER
# use single-quoted source strings
class TestPreproc < Test::Unit::TestCase
def load txt, bt = caller.first
p = Metasm::Preprocessor.new
bt =~ /^(.*?):(\d+)/
p.feed txt, $1, $2.to_i+1
p
end
def test_gettok
p = load <<'EOS'
test boo
" bla bla\
\"\\" \
xx
EOS
assert_equal \
['test', :space, :string, :eol, :quoted, :space, 'xx', :eol, true],
[p.readtok.raw, p.readtok.type, p.readtok.type, p.readtok.type, p.readtok.type, p.readtok.type, p.readtok.raw, p.readtok.type, p.eos?]
end
def test_comment
p = load <<'EOS'
foo /* bar * /*/ baz
kikoo // lol \
asv
EOS
toks = []
nil while tok = p.readtok and (tok.type == :space or tok.type == :eol)
until p.eos?
toks << tok.raw
nil while tok = p.readtok and (tok.type == :space or tok.type == :eol)
end
assert_equal %w[foo baz kikoo], toks
end
def test_preproc
# ignores eol/space at begin/end
t_preparse = proc { |text, result|
p = load text, caller.first
txt = ''
t = nil
txt << t.raw until p.eos? or not t = p.readtok
assert_equal(result, txt.strip)
}
t_preparse[<<EOS, '']
#if 0 // test # as first char
toto
#endif
EOS
t_preparse[<<EOS, 'coucou']
#define tutu
#if defined ( tutu )
tutu coucou
#endif
EOS
t_preparse['a #define b', 'a #define b']
t_preparse[<<EOS, "// true !\nblu"]
#ifdef toto // this is false
bla
#elif .2_3e-4 > 2 /* this one too */
blo
#elif (1+1)*2 > 2 // true !
blu
#elif 4 > 2 // not you
ble
#else
bli
#endif
EOS
t_preparse[<<'EOS', 'ab#define x']
a\
b\
#define x
EOS
p = load('__LINE__,__DATE__,__TIME__')
assert_equal(__LINE__, p.readtok.value) ; p.readtok
assert_not_equal('__DATE__', p.readtok.raw) ; p.readtok
assert_not_equal('__TIME__', p.readtok.raw)
t_preparse[<<EOS, 'toto 1 toto 12 toto 3+(3-2) otot hoho']
#define azer(k) 12
# define xxx azer(7)
#define macro(a, b, c) toto a toto b toto c otot
macro(1, xxx, 3+(3-2)) hoho
EOS
t_preparse[<<EOS, 'c']
#define a b
#define d c
#define c d
#define b c
a
EOS
t_preparse[<<EOS, 'b']
#define b c
#define a b
#undef b
a
EOS
t_preparse[<<EOS, 'toto tutu huhu()']
#define toto() abcd
#define tata huhu
toto tutu tata()
EOS
t_preparse[<<EOS, '"haha"']
#define d(a) #a
d(haha)
EOS
t_preparse[<<EOS, '{']
#define toto(a) a
toto({)
EOS
t_preparse[<<EOS, 'x(, 1)']
#define d(a,b) x(a, b)
d(,1)
EOS
t_preparse[<<EOS, '"foo" "4"']
#define str(x) #x
#define xstr(x) str(x)
#define foo 4
str(foo) xstr(foo)
EOS
Metasm::Preprocessor.include_search_path << '.'
begin
File.open('tests/prepro_testinclude.asm', 'w') { |fd| fd.puts '#define out in' }
t_preparse[<<EOS, 'in']
#include <tests/prepro_testinclude.asm>
out
EOS
ensure
File.unlink('tests/prepro_testinclude.asm') rescue nil
end
p = load <<EOS
#define cct(a, b) a ## _ ## b
cct(toto, tutu)
EOS
nil while tok = p.readtok and (tok.type == :space or tok.type == :eol)
assert_equal('toto_tutu', tok.raw) # check we get only 1 token back
# assert_outputs_a_warning ?
t_preparse[<<EOS, <<EOS.strip]
#define va1(a, b...) toto(a, ##b)
#define va3(a, ...) toto(a, __VA_ARGS__)
va1(1, 2);
va1(1,2);
va1(1);
va3(1, 2);
va3(1);
EOS
toto(1, 2);
toto(1,2);
toto(1);
toto(1, 2);
toto(1, );
EOS
t_preparse[<<EOS, "#define a c\n#define b d\na b"]
#define x(z) z
#define y #define
x(#)define a c
y b d
a b
EOS
t_preparse["#define a(a) a(a)\na(1)", '1(1)']
t_preparse["#if 0\n#endif", '']
t_preparse["#if 0U\n#endif", '']
t_preparse["#if 0L\n#endif", '']
t_preparse["#if 0LLU\n#endif", '']
end
def test_floats
t_float = proc { |txt|
text = <<EOS
#if #{txt}
1
#endif
EOS
p = load text, caller.first
txt = ''
t = nil
txt << t.raw until p.eos? or not t = p.readtok
assert_equal('1', txt.strip)
}
t_float['1 > 0']
t_float['1.0 > 0']
t_float['1e2 > 10 && 1.0e2 < 1000']
t_float['1.0e+2 > 10']
t_float['10_00e-2 > 1 && 10_00e-2 < 100']
t_float['.1e2 > 1']
#t_float['0x1.p2L > 1 && 0x1p2f < 5']
t_float['0x1.p2L > 1']
t_float['0x1p2f < 5']
end
def test_errors
test_err = proc { |txt| assert_raise(Metasm::ParseError) { p = load(txt, caller.first) ; p.readtok until p.eos? } }
t_float = proc { |txt| assert_raise(Metasm::ParseError) { p = load("#if #{txt}\n#endif", caller.first) ; p.readtok } }
test_err["\"abc\n\""]
test_err['"abc\x"']
test_err['/*']
test_err['#if 0']
test_err["#define toto(tutu,"]
test_err["#define toto( (tutu, tata)"]
test_err['#error bla']
test_err[<<EOS]
#if 0
#elif 1
#else
#if 2
#endif
EOS
test_err[<<EOS]
#define abc(def)
abc (1, 3)
EOS
test_err["#if 0LUL\n#endif"]
# warnings only
#test_err["#define aa\n#define aa"]
#test_err['#define a(b) #c']
#test_err['#define a(b, b)']
#test_err['#define a ##z']
t_float['1e++4']
t_float['1.0e 4']
t_float['_1.0']
t_float['.e2']
t_float['1.1e+_1']
t_float['.2e']
t_float['.']
t_float['1.2e*4']
t_float['0x1.e4']
t_float['0x1.p4a']
t_float['0x.p1']
t_float['0x.1lp1']
end
end