diff --git a/spec/compiler/lexer/lexer_spec.cr b/spec/compiler/lexer/lexer_spec.cr index 15539827385f59ecb5970e20676496bd6cdb7fdf..c21d2f5df7ccf9c566962e5e3340b3d681de1052 100755 --- a/spec/compiler/lexer/lexer_spec.cr +++ b/spec/compiler/lexer/lexer_spec.cr @@ -123,18 +123,6 @@ def it_lexes_global_match(globals) end end -def it_raises_doesnt_fit_in_integer(string, message) - it "errors if can't fit #{string} in integer" do - lexer = Lexer.new(string) - begin - lexer.next_token - fail "expected to raise" - rescue ex : Crystal::SyntaxException - ex.message.should eq(message) - end - end -end - describe "Lexer" do it_lexes "", :EOF it_lexes " ", :SPACE @@ -227,28 +215,28 @@ describe "Lexer" do it_lexes_regex "/foo\\sbar/", "foo\\sbar" it_lexes_global_match ["$1", "$10"] - it_raises_doesnt_fit_in_integer "128_i8", "128 doesn't fit in an Int8" - it_raises_doesnt_fit_in_integer "-129_i8", "-129 doesn't fit in an Int8" - it_raises_doesnt_fit_in_integer "256_u8", "256 doesn't fit in an UInt8" - it_raises_doesnt_fit_in_integer "-1_u8", "Invalid negative value -1 for UInt8" + assert_syntax_error "128_i8", "128 doesn't fit in an Int8" + assert_syntax_error "-129_i8", "-129 doesn't fit in an Int8" + assert_syntax_error "256_u8", "256 doesn't fit in an UInt8" + assert_syntax_error "-1_u8", "Invalid negative value -1 for UInt8" - it_raises_doesnt_fit_in_integer "32768_i16", "32768 doesn't fit in an Int16" - it_raises_doesnt_fit_in_integer "-32769_i16", "-32769 doesn't fit in an Int16" - it_raises_doesnt_fit_in_integer "65536_u16", "65536 doesn't fit in an UInt16" - it_raises_doesnt_fit_in_integer "-1_u16", "Invalid negative value -1 for UInt16" + assert_syntax_error "32768_i16", "32768 doesn't fit in an Int16" + assert_syntax_error "-32769_i16", "-32769 doesn't fit in an Int16" + assert_syntax_error "65536_u16", "65536 doesn't fit in an UInt16" + assert_syntax_error "-1_u16", "Invalid negative value -1 for UInt16" - it_raises_doesnt_fit_in_integer "2147483648_i32", "2147483648 doesn't fit in an Int32" - it_raises_doesnt_fit_in_integer "-2147483649_i32", "-2147483649 doesn't fit in an Int32" - it_raises_doesnt_fit_in_integer "4294967296_u32", "4294967296 doesn't fit in an UInt32" - it_raises_doesnt_fit_in_integer "-1_u32", "Invalid negative value -1 for UInt32" + assert_syntax_error "2147483648_i32", "2147483648 doesn't fit in an Int32" + assert_syntax_error "-2147483649_i32", "-2147483649 doesn't fit in an Int32" + assert_syntax_error "4294967296_u32", "4294967296 doesn't fit in an UInt32" + assert_syntax_error "-1_u32", "Invalid negative value -1 for UInt32" - it_raises_doesnt_fit_in_integer "9223372036854775808_i64", "9223372036854775808 doesn't fit in an Int64" - it_raises_doesnt_fit_in_integer "-9223372036854775809_i64", "-9223372036854775809 doesn't fit in an Int64" - it_raises_doesnt_fit_in_integer "118446744073709551616_u64", "118446744073709551616 doesn't fit in an UInt64" - it_raises_doesnt_fit_in_integer "18446744073709551616_u64", "18446744073709551616 doesn't fit in an UInt64" - it_raises_doesnt_fit_in_integer "-1_u64", "Invalid negative value -1 for UInt64" + assert_syntax_error "9223372036854775808_i64", "9223372036854775808 doesn't fit in an Int64" + assert_syntax_error "-9223372036854775809_i64", "-9223372036854775809 doesn't fit in an Int64" + assert_syntax_error "118446744073709551616_u64", "118446744073709551616 doesn't fit in an UInt64" + assert_syntax_error "18446744073709551616_u64", "18446744073709551616 doesn't fit in an UInt64" + assert_syntax_error "-1_u64", "Invalid negative value -1 for UInt64" - it_raises_doesnt_fit_in_integer "18446744073709551616", "18446744073709551616 doesn't fit in an UInt64" + assert_syntax_error "18446744073709551616", "18446744073709551616 doesn't fit in an UInt64" it "lexes not instance var" do lexer = Lexer.new "!@foo" @@ -325,25 +313,8 @@ describe "Lexer" do token.type.should eq(:EOF) end - it "raises unterminated regular expression" do - lexer = Lexer.new("/foo") - begin - lexer.next_token - fail "expected to raise" - rescue ex : Crystal::SyntaxException - ex.message.should eq("unterminated regular expression") - end - end - - it "raises unterminated quoted symbol" do - lexer = Lexer.new(":\"foo") - begin - lexer.next_token - fail "expected to raise" - rescue ex : Crystal::SyntaxException - ex.message.should eq("unterminated quoted symbol") - end - end + assert_syntax_error "/foo", "unterminated regular expression" + assert_syntax_error ":\"foo", "unterminated quoted symbol" it "lexes utf-8 char" do lexer = Lexer.new "'á'" @@ -375,13 +346,5 @@ describe "Lexer" do token.type.should eq(:NUMBER) end - it "raises if slash r without slash n" do - lexer = Lexer.new("\r1") - begin - lexer.next_token - fail "expected to raise" - rescue ex : Crystal::SyntaxException - ex.message.should eq("expected '\\n' after '\\r'") - end - end + assert_syntax_error "\r1", "expected '\\n' after '\\r'" end diff --git a/spec/compiler/parser/parser_spec.cr b/spec/compiler/parser/parser_spec.cr index 709c62a08c5696d6e2691c0ca4012404afe0cc4a..1c2e0284015543d9b750737990a01fb8a98f1162 100755 --- a/spec/compiler/parser/parser_spec.cr +++ b/spec/compiler/parser/parser_spec.cr @@ -81,7 +81,7 @@ class String end def symbol - Crystal::SymbolLiteral.new self + SymbolLiteral.new self end def static_array_of(size) @@ -106,8 +106,6 @@ def it_parses(string, expected_node) end end -include Crystal - describe "Parser" do it_parses "nil", NilLiteral.new @@ -555,24 +553,24 @@ describe "Parser" do it_parses "$foo", Global.new("$foo") - it_parses "macro foo;end", Crystal::Macro.new("foo", [] of Arg, Expressions.from([] of ASTNode)) - it_parses %(macro foo; 1 + 2; end), Crystal::Macro.new("foo", [] of Arg, Expressions.from([" 1 + 2; ".macro_literal] of ASTNode)) - it_parses %(macro foo x; 1 + 2; end), Crystal::Macro.new("foo", ([Arg.new("x")]), Expressions.from([" 1 + 2; ".macro_literal] of ASTNode)) - it_parses %(macro foo x\n 1 + 2; end), Crystal::Macro.new("foo", ([Arg.new("x")]), Expressions.from([" 1 + 2; ".macro_literal] of ASTNode)) - it_parses %(macro foo(x); 1 + 2; end), Crystal::Macro.new("foo", ([Arg.new("x")]), Expressions.from([" 1 + 2; ".macro_literal] of ASTNode)) - it_parses %(macro foo(x)\n 1 + 2; end), Crystal::Macro.new("foo", ([Arg.new("x")]), Expressions.from([" 1 + 2; ".macro_literal] of ASTNode)) - it_parses "macro foo; 1 + 2 {{foo}} 3 + 4; end", Crystal::Macro.new("foo", [] of Arg, Expressions.from([" 1 + 2 ".macro_literal, MacroExpression.new("foo".var), " 3 + 4; ".macro_literal] of ASTNode)) - it_parses "macro foo; 1 + 2 {{ foo }} 3 + 4; end", Crystal::Macro.new("foo", [] of Arg, Expressions.from([" 1 + 2 ".macro_literal, MacroExpression.new("foo".var), " 3 + 4; ".macro_literal] of ASTNode)) - it_parses "macro foo;bar{% for x in y %}body{% end %}baz;end", Crystal::Macro.new("foo", [] of Arg, Expressions.from(["bar".macro_literal, MacroFor.new(["x".var], "y".var, "body".macro_literal), "baz;".macro_literal] of ASTNode)) - it_parses "macro foo;bar{% for x, y in z %}body{% end %}baz;end", Crystal::Macro.new("foo", [] of Arg, Expressions.from(["bar".macro_literal, MacroFor.new(["x".var, "y".var], "z".var, "body".macro_literal), "baz;".macro_literal] of ASTNode)) - it_parses "macro foo;bar{% if x %}body{% end %}baz;end", Crystal::Macro.new("foo", [] of Arg, Expressions.from(["bar".macro_literal, MacroIf.new("x".var, "body".macro_literal), "baz;".macro_literal] of ASTNode)) - it_parses "macro foo;bar{% if x %}body{% else %}body2{%end%}baz;end", Crystal::Macro.new("foo", [] of Arg, Expressions.from(["bar".macro_literal, MacroIf.new("x".var, "body".macro_literal, "body2".macro_literal), "baz;".macro_literal] of ASTNode)) - it_parses "macro foo;bar{% if x %}body{% elsif y %}body2{%end%}baz;end", Crystal::Macro.new("foo", [] of Arg, Expressions.from(["bar".macro_literal, MacroIf.new("x".var, "body".macro_literal, MacroIf.new("y".var, "body2".macro_literal)), "baz;".macro_literal] of ASTNode)) - it_parses "macro foo;bar{% unless x %}body{% end %}baz;end", Crystal::Macro.new("foo", [] of Arg, Expressions.from(["bar".macro_literal, MacroIf.new("x".var, Nop.new, "body".macro_literal), "baz;".macro_literal] of ASTNode)) - - it_parses "macro foo;bar{% for x in y %}\\ \n body{% end %}baz;end", Crystal::Macro.new("foo", [] of Arg, Expressions.from(["bar".macro_literal, MacroFor.new(["x".var], "y".var, "body".macro_literal), "baz;".macro_literal] of ASTNode)) - it_parses "macro foo;bar{% for x in y %}\\ \n body{% end %}\\ baz;end", Crystal::Macro.new("foo", [] of Arg, Expressions.from(["bar".macro_literal, MacroFor.new(["x".var], "y".var, "body".macro_literal), "baz;".macro_literal] of ASTNode)) - it_parses "macro foo; 1 + 2 {{foo}}\\ 3 + 4; end", Crystal::Macro.new("foo", [] of Arg, Expressions.from([" 1 + 2 ".macro_literal, MacroExpression.new("foo".var), "3 + 4; ".macro_literal] of ASTNode)) + it_parses "macro foo;end", Macro.new("foo", [] of Arg, Expressions.from([] of ASTNode)) + it_parses %(macro foo; 1 + 2; end), Macro.new("foo", [] of Arg, Expressions.from([" 1 + 2; ".macro_literal] of ASTNode)) + it_parses %(macro foo x; 1 + 2; end), Macro.new("foo", ([Arg.new("x")]), Expressions.from([" 1 + 2; ".macro_literal] of ASTNode)) + it_parses %(macro foo x\n 1 + 2; end), Macro.new("foo", ([Arg.new("x")]), Expressions.from([" 1 + 2; ".macro_literal] of ASTNode)) + it_parses %(macro foo(x); 1 + 2; end), Macro.new("foo", ([Arg.new("x")]), Expressions.from([" 1 + 2; ".macro_literal] of ASTNode)) + it_parses %(macro foo(x)\n 1 + 2; end), Macro.new("foo", ([Arg.new("x")]), Expressions.from([" 1 + 2; ".macro_literal] of ASTNode)) + it_parses "macro foo; 1 + 2 {{foo}} 3 + 4; end", Macro.new("foo", [] of Arg, Expressions.from([" 1 + 2 ".macro_literal, MacroExpression.new("foo".var), " 3 + 4; ".macro_literal] of ASTNode)) + it_parses "macro foo; 1 + 2 {{ foo }} 3 + 4; end", Macro.new("foo", [] of Arg, Expressions.from([" 1 + 2 ".macro_literal, MacroExpression.new("foo".var), " 3 + 4; ".macro_literal] of ASTNode)) + it_parses "macro foo;bar{% for x in y %}body{% end %}baz;end", Macro.new("foo", [] of Arg, Expressions.from(["bar".macro_literal, MacroFor.new(["x".var], "y".var, "body".macro_literal), "baz;".macro_literal] of ASTNode)) + it_parses "macro foo;bar{% for x, y in z %}body{% end %}baz;end", Macro.new("foo", [] of Arg, Expressions.from(["bar".macro_literal, MacroFor.new(["x".var, "y".var], "z".var, "body".macro_literal), "baz;".macro_literal] of ASTNode)) + it_parses "macro foo;bar{% if x %}body{% end %}baz;end", Macro.new("foo", [] of Arg, Expressions.from(["bar".macro_literal, MacroIf.new("x".var, "body".macro_literal), "baz;".macro_literal] of ASTNode)) + it_parses "macro foo;bar{% if x %}body{% else %}body2{%end%}baz;end", Macro.new("foo", [] of Arg, Expressions.from(["bar".macro_literal, MacroIf.new("x".var, "body".macro_literal, "body2".macro_literal), "baz;".macro_literal] of ASTNode)) + it_parses "macro foo;bar{% if x %}body{% elsif y %}body2{%end%}baz;end", Macro.new("foo", [] of Arg, Expressions.from(["bar".macro_literal, MacroIf.new("x".var, "body".macro_literal, MacroIf.new("y".var, "body2".macro_literal)), "baz;".macro_literal] of ASTNode)) + it_parses "macro foo;bar{% unless x %}body{% end %}baz;end", Macro.new("foo", [] of Arg, Expressions.from(["bar".macro_literal, MacroIf.new("x".var, Nop.new, "body".macro_literal), "baz;".macro_literal] of ASTNode)) + + it_parses "macro foo;bar{% for x in y %}\\ \n body{% end %}baz;end", Macro.new("foo", [] of Arg, Expressions.from(["bar".macro_literal, MacroFor.new(["x".var], "y".var, "body".macro_literal), "baz;".macro_literal] of ASTNode)) + it_parses "macro foo;bar{% for x in y %}\\ \n body{% end %}\\ baz;end", Macro.new("foo", [] of Arg, Expressions.from(["bar".macro_literal, MacroFor.new(["x".var], "y".var, "body".macro_literal), "baz;".macro_literal] of ASTNode)) + it_parses "macro foo; 1 + 2 {{foo}}\\ 3 + 4; end", Macro.new("foo", [] of Arg, Expressions.from([" 1 + 2 ".macro_literal, MacroExpression.new("foo".var), "3 + 4; ".macro_literal] of ASTNode)) it_parses "def foo : String; 1; end", Def.new("foo", [] of Arg, [MacroLiteral.new(" 1; ")] of ASTNode, nil, nil, "String".path) it_parses "def foo(x) : String; 1; end", Def.new("foo", ["x".arg], [MacroLiteral.new(" 1; ")] of ASTNode, nil, nil, "String".path) @@ -821,110 +819,30 @@ describe "Parser" do node.instance_vars.should eq(Set.new(["@x"])) end - it "errors if arg doesn't have a default value after a previous one has one" do - assert_syntax_error "def foo(x = 1, y); end", - "argument must have a default value" - end - - it "says unterminated array literal" do - begin - Parser.parse(" [1, 2, 3 end") - rescue ex : Crystal::SyntaxException - ex.message.not_nil!.includes?("unterminated array literal").should be_true - ex.line_number.should eq(1) - ex.column_number.should eq(2) - end - end - - it "says unterminated hash literal" do - begin - Parser.parse(" {1 => end") - rescue ex : Crystal::SyntaxException - ex.message.not_nil!.includes?("unterminated hash literal").should be_true - ex.line_number.should eq(1) - ex.column_number.should eq(2) - end - end - - it "says unterminated tuple literal" do - begin - Parser.parse(" {1, 2, 3 end") - rescue ex : Crystal::SyntaxException - ex.message.not_nil!.includes?("unterminated tuple literal").should be_true - ex.line_number.should eq(1) - ex.column_number.should eq(2) - end - end - - it "says unterminated parenthesized expression" do - begin - Parser.parse(" (1, 2, 3 end") - rescue ex : Crystal::SyntaxException - ex.message.not_nil!.includes?("unterminated parenthesized expression").should be_true - ex.line_number.should eq(1) - ex.column_number.should eq(2) - end - end - - it "says unterminated call" do - begin - Parser.parse("foo(1, 2, 3 end") - rescue ex : Crystal::SyntaxException - ex.message.not_nil!.includes?("unterminated call").should be_true - ex.line_number.should eq(1) - ex.column_number.should eq(4) - end - end - - it "says unterminated call with block arg" do - begin - Parser.parse("foo(foo(&.block)") - rescue ex : Crystal::SyntaxException - ex.message.not_nil!.includes?("unterminated call").should be_true - ex.line_number.should eq(1) - ex.column_number.should eq(4) - end - end - - it "can't parse implicit call in value-less case" do - begin - Parser.parse("case when .foo? then 1; end") - fail "syntax exception should have been raised" - rescue ex : Crystal::SyntaxException - end - end - - it "says unexpected end in macro" do - begin - Parser.parse "macro foo;{%end};end" - fail "syntax exception should have been raised" - rescue ex : Crystal::SyntaxException - end - end - - it "says unexpected token on comma in curly block" do - begin - Parser.parse "foo {1, 2}" - fail "syntax exception should have been raised" - rescue ex : Crystal::SyntaxException - ex.message.not_nil!.includes?("unexpected token: }").should be_true - end - end - - it "says error on pointerof(self)" do - begin - Parser.parse "pointerof(self)" - fail "syntax exception should have been raised" - rescue ex : Crystal::SyntaxException - ex.message.not_nil!.includes?("can't take pointerof(self)").should be_true - end - end - - it "says error on def foo 1" do - begin - Parser.parse "def foo 1; end" - fail "syntax exception should have been raised" - rescue ex : Crystal::SyntaxException - end - end + assert_syntax_error "def foo(x = 1, y); end", + "argument must have a default value" + + assert_syntax_error " [1, 2, 3 end", + "unterminated array literal", 1, 2 + + assert_syntax_error " {1 => end", + "unterminated hash literal", 1, 2 + + assert_syntax_error " {1, 2, 3 end", + "unterminated tuple literal", 1, 2 + + assert_syntax_error " (1, 2, 3 end", + "unterminated parenthesized expression", 1, 2 + + assert_syntax_error "foo(1, 2, 3 end", + "unterminated call", 1, 4 + + assert_syntax_error "foo(foo(&.block)", + "unterminated call", 1, 4 + + assert_syntax_error "case when .foo? then 1; end" + assert_syntax_error "macro foo;{%end};end" + assert_syntax_error "foo {1, 2}", "unexpected token: }" + assert_syntax_error "pointerof(self)", "can't take pointerof(self)" + assert_syntax_error "def foo 1; end" end diff --git a/spec/compiler/type_inference/block_spec.cr b/spec/compiler/type_inference/block_spec.cr index 19cabc3807f6a56be06c9f4274dce7543bd97caa..24bca74569ca36e8a8c60518bfc78b0b09013bd6 100755 --- a/spec/compiler/type_inference/block_spec.cr +++ b/spec/compiler/type_inference/block_spec.cr @@ -285,10 +285,8 @@ describe "Block inference" do "expected block to return Foo, not Int32" end - it "errors when block varaible shadows local variable" do - assert_syntax_error "a = 1; foo { |a| }", - "block argument 'a' shadows local variable 'a'" - end + assert_syntax_error "a = 1; foo { |a| }", + "block argument 'a' shadows local variable 'a'" it "errors when using local varaible with block argument name" do assert_error "def foo; yield; end; foo { |a| }; a", diff --git a/spec/compiler/type_inference/exception_spec.cr b/spec/compiler/type_inference/exception_spec.cr index 8923fd2396927a2820051cc6846d27f9a495959d..10a4af87d405f1d03cf87795a84bef7930fa6745 100644 --- a/spec/compiler/type_inference/exception_spec.cr +++ b/spec/compiler/type_inference/exception_spec.cr @@ -137,9 +137,8 @@ describe "Type inference: exception" do ") { |mod| union_of(mod.int32, mod.nil) } end - it "errors if exception var shadows local var" do - assert_syntax_error "ex = 1; begin; rescue ex; end", "exception variable 'ex' shadows local variable 'ex'" - end + assert_syntax_error "ex = 1; begin; rescue ex; end", + "exception variable 'ex' shadows local variable 'ex'" it "errors if catched exception is not a subclass of Exception" do assert_error "begin; rescue ex : Int32; end", "Int32 is not a subclass of Exception" @@ -153,17 +152,14 @@ describe "Type inference: exception" do assert_error "begin; rescue ex; end; ex", "undefined local variable or method 'ex'" end - it "errors if catch-all rescue before specific rescue" do - assert_syntax_error "begin; rescue ex; rescue ex : Foo; end; ex", "specific rescue must come before catch-all rescue" - end + assert_syntax_error "begin; rescue ex; rescue ex : Foo; end; ex", + "specific rescue must come before catch-all rescue" - it "errors if catch-all rescue specified twice" do - assert_syntax_error "begin; rescue ex; rescue; end; ex", "catch-all rescue can only be specified once" - end + assert_syntax_error "begin; rescue ex; rescue; end; ex", + "catch-all rescue can only be specified once" - it "errors if else without rescue" do - assert_syntax_error "begin; else; 1; end", "'else' is useless without 'rescue'" - end + assert_syntax_error "begin; else; 1; end", + "'else' is useless without 'rescue'" it "types code with abstract exception that delegates method" do assert_type(%( diff --git a/spec/compiler/type_inference/fun_spec.cr b/spec/compiler/type_inference/fun_spec.cr index 8745370e15852a6f1dab0127fbbea2fe1e7dea09..f7272fa0609b3ced5e768f3a61c013c924c27331 100644 --- a/spec/compiler/type_inference/fun_spec.cr +++ b/spec/compiler/type_inference/fun_spec.cr @@ -67,10 +67,8 @@ describe "Type inference: fun" do ") { float64 } end - it "errors when fun varaible shadows local variable" do - assert_syntax_error "a = 1; ->(a : Foo) { }", - "function argument 'a' shadows local variable 'a'" - end + assert_syntax_error "a = 1; ->(a : Foo) { }", + "function argument 'a' shadows local variable 'a'" it "errors when using local varaible with fun argument name" do assert_error "->(a : Int32) { }; a", diff --git a/spec/compiler/type_inference/var_spec.cr b/spec/compiler/type_inference/var_spec.cr index c8f8c44b795262a52ba3a2014fcfe5b63aba5e5c..a5ee9c3e2a50fb5b0383f6fa97c785bc651196da 100755 --- a/spec/compiler/type_inference/var_spec.cr +++ b/spec/compiler/type_inference/var_spec.cr @@ -37,10 +37,8 @@ describe "Type inference: var" do ", "undefined local variable or method 'something'" end - it "reports read before assignment" do - assert_syntax_error "a += 1", - "'+=' before definition of 'a'" - end + assert_syntax_error "a += 1", + "'+=' before definition of 'a'" it "reports read before assignment" do assert_error "a = a + 1", @@ -51,9 +49,8 @@ describe "Type inference: var" do assert_error "self", "there's no self in this scope" end - it "reports can't change the value of self" do - assert_syntax_error "self = 1", "can't change the value of self" - end + assert_syntax_error "self = 1", + "can't change the value of self" it "reports variable always nil" do assert_error "1 == 2 ? (a = 1) : a", diff --git a/spec/spec_helper.cr b/spec/spec_helper.cr index 41ceeabf000c555835ddd5f4966bbed85e26b5d5..15873697d15a321e3c76ccb068a1b435d3bfe7b1 100644 --- a/spec/spec_helper.cr +++ b/spec/spec_helper.cr @@ -72,22 +72,41 @@ def assert_after_type_inference(before, after) result.node.to_s.strip.should eq(after.strip) end +def assert_syntax_error(str) + it "says syntax error on #{str.inspect}" do + expect_raises Crystal::SyntaxException do + parse str + end + end +end + def assert_syntax_error(str, message) - begin - parse str - fail "SyntaxException wasn't raised" - rescue ex : Crystal::SyntaxException - fail "Expected '#{ex}' to contain '#{message}'" unless ex.to_s.includes? message + it "says syntax error on #{str.inspect}" do + expect_raises Crystal::SyntaxException, message do + parse str + end + end +end + +def assert_syntax_error(str, message, line, column) + it "says syntax error on #{str.inspect}" do + begin + Parser.parse(str) + fail "expected SyntaxException to be raised" + rescue ex : SyntaxException + ex.message.not_nil!.includes?(message).should be_true + ex.line_number.should eq(line) + ex.column_number.should eq(column) + end end end def assert_error(str, message) - nodes = parse str - begin - infer_type nodes - fail "TypeException wasn't raised" - rescue ex : Crystal::TypeException - fail "Expected '#{ex}' to contain '#{message}'" unless ex.to_s.includes? message + it "says type error on #{str.inspect}" do + nodes = parse str + expect_raises TypeException, message do + infer_type nodes + end end end diff --git a/spec/std/array_spec.cr b/spec/std/array_spec.cr index 48ae29838fa9de45c34c9a904fdeb0432c88a19e..79d615eccd47c91c2a0e3df3191167ab1e4062fe 100755 --- a/spec/std/array_spec.cr +++ b/spec/std/array_spec.cr @@ -144,11 +144,9 @@ describe "Array" do end it "deletes out of bounds" do - begin - a = [1, 2, 3, 4] + a = [1, 2, 3, 4] + expect_raises IndexOutOfBounds do a.delete_at(4) - fail "Expected to raise IndexOutOfBounds" - rescue IndexOutOfBounds end end end @@ -303,10 +301,8 @@ describe "Array" do end it "raises if out of bounds" do - begin + expect_raises IndexOutOfBounds do [1, 2, 3][4] - fail "Expected [] to raise" - rescue IndexOutOfBounds end end @@ -324,10 +320,8 @@ describe "Array" do end it "raises when empty" do - begin + expect_raises IndexOutOfBounds do ([] of Int32).pop - fail "expected to raise IndexOutOfBounds" - rescue IndexOutOfBounds end end @@ -346,11 +340,9 @@ describe "Array" do end it "pops negative count raises" do - begin - a = [1, 2] + a = [1, 2] + expect_raises ArgumentError do a.pop(-1) - fail "exepcted to raise ArgumentError" - rescue ArgumentError end end end @@ -363,10 +355,8 @@ describe "Array" do end it "raises when empty" do - begin + expect_raises IndexOutOfBounds do ([] of Int32).shift - fail "expected to raise IndexOutOfBounds" - rescue IndexOutOfBounds end end @@ -385,11 +375,9 @@ describe "Array" do end it "shifts negative count raises" do - begin - a = [1, 2] + a = [1, 2] + expect_raises ArgumentError do a.shift(-1) - fail "exepcted to raise ArgumentError" - rescue ArgumentError end end end @@ -401,10 +389,8 @@ describe "Array" do end it "raises when empty" do - begin + expect_raises IndexOutOfBounds do ([] of Int32).first - fail "expected to raise IndexOutOfBounds" - rescue IndexOutOfBounds end end end @@ -427,10 +413,8 @@ describe "Array" do end it "raises when empty" do - begin + expect_raises IndexOutOfBounds do ([] of Int32).last - fail "expected to raise IndexOutOfBounds" - rescue IndexOutOfBounds end end end @@ -513,10 +497,8 @@ describe "Array" do end it "gets sample of negative count elements raises" do - begin + expect_raises ArgumentError do [1].sample(-1) - fail "expected to raise ArgumentError" - rescue ArgumentError end end @@ -590,19 +572,15 @@ describe "Array" do it "swaps but raises out of bounds on left" do a = [1, 2, 3] - begin + expect_raises IndexOutOfBounds do a.swap(3, 0) - fail "expected swap to fail" - rescue IndexOutOfBounds end end it "swaps but raises out of bounds on right" do a = [1, 2, 3] - begin + expect_raises IndexOutOfBounds do a.swap(0, 3) - fail "expected swap to fail" - rescue IndexOutOfBounds end end end diff --git a/spec/std/bit_array_spec.cr b/spec/std/bit_array_spec.cr index aadfafdef37966cccb273628616a2cb33989515d..01674c9f671b0871b36095704843f9fe5c30d5f4 100644 --- a/spec/std/bit_array_spec.cr +++ b/spec/std/bit_array_spec.cr @@ -50,10 +50,8 @@ describe "BitArray" do it "is raises when out of bounds" do ary = BitArray.new(10) - begin + expect_raises IndexOutOfBounds do ary[10] = true - fail "expected IndexOutOfBounds to be raised" - rescue IndexOutOfBounds end end diff --git a/spec/std/cast_spec.cr b/spec/std/cast_spec.cr index d3131cfb6941683c5df52d5dd1d966b9daa9353f..0baaa73cec5e11809419a2dead778fe1ea369f0c 100644 --- a/spec/std/cast_spec.cr +++ b/spec/std/cast_spec.cr @@ -40,11 +40,8 @@ describe "Cast" do it "casts from union to single type raises" do a = 1 || 'a' - begin + expect_raises Exception, "type cast exception" do a as Char - fail "expected cast to raise" - rescue ex - ex.message.should eq("type cast exception") end end @@ -56,11 +53,8 @@ describe "Cast" do pending "casts from union to another union raises" do a = 1 || 1.5 || 'a' - begin + expect_raises Exception, "type cast exception" do a as Float64 | Char - fail "expected cast to raise" - rescue ex - ex.message.should eq("type cast exception") end end @@ -72,11 +66,8 @@ describe "Cast" do it "casts from hierarchy to single type raises" do a = CastSpecBar.new || CastSpecFoo.new || CastSpecBaz.new - begin + expect_raises Exception, "type cast exception" do a as CastSpecBaz - fail "expected cast to raise" - rescue ex - ex.message.should eq("type cast exception") end end diff --git a/spec/std/char_reader_spec.cr b/spec/std/char_reader_spec.cr index c4cabf64641d0083dfb31a70ab99f38fbf173bf0..ac955a10912743eee18d0fdfe613c6d2ad54ff86 100644 --- a/spec/std/char_reader_spec.cr +++ b/spec/std/char_reader_spec.cr @@ -9,7 +9,7 @@ describe "CharReader" do reader.current_char.ord.should eq(0) reader.has_next?.should be_false - expect_raise IndexOutOfBounds do + expect_raises IndexOutOfBounds do reader.next_char end end @@ -22,7 +22,7 @@ describe "CharReader" do reader.next_char.ord.should eq(0) reader.has_next?.should be_false - expect_raise IndexOutOfBounds do + expect_raises IndexOutOfBounds do reader.next_char end end @@ -46,7 +46,7 @@ describe "CharReader" do reader.next_char.ord.should eq(0) reader.has_next?.should be_false - expect_raise IndexOutOfBounds do + expect_raises IndexOutOfBounds do reader.next_char end end diff --git a/spec/std/dir_spec.cr b/spec/std/dir_spec.cr index f3ba9d6b0c73a4498610016ceafe1f0589ebe406..5cb6d672bbd50488a95260d40cea729cc80554a6 100755 --- a/spec/std/dir_spec.cr +++ b/spec/std/dir_spec.cr @@ -23,10 +23,8 @@ describe "Dir" do end it "tests mkdir with an existing path" do - begin + expect_raises Errno do Dir.mkdir(__DIR__, 0700) - fail "Expected Errno to be raised" - rescue Errno end end @@ -34,33 +32,27 @@ describe "Dir" do path = "/tmp/crystal_mkdir_ptest_#{Process.pid}/" Dir.mkdir_p(path).should eq(0) Dir.exists?(path).should be_true - path = File.join({path, "a", "b", "c"}) + path = File.join({path, "a", "b", "c"}) Dir.mkdir_p(path).should eq(0) Dir.exists?(path).should be_true end it "tests mkdir_p with an existing path" do Dir.mkdir_p(__DIR__).should eq(0) - begin + expect_raises Errno do Dir.mkdir_p(__FILE__) - fail "Expected Errno to be raised" - rescue Errno end end it "tests rmdir with an nonexistent path" do - begin + expect_raises Errno do Dir.rmdir("/tmp/crystal_mkdir_test_#{Process.pid}/") - fail "Expected Errno to be raised" - rescue Errno end end it "tests rmdir with a path that cannot be removed" do - begin + expect_raises Errno do Dir.rmdir(__DIR__) - fail "Expected Errno to be raised" - rescue Errno end end end diff --git a/spec/std/enumerable_spec.cr b/spec/std/enumerable_spec.cr index 8ed37eab2613b2f63872a6c53b145697c02a91d0..c532091a2d17cd280972226c938c7fb8f65f5df8 100755 --- a/spec/std/enumerable_spec.cr +++ b/spec/std/enumerable_spec.cr @@ -21,10 +21,8 @@ describe "Enumerable" do assert { [1, 2, 3].inject(10) { |memo, i| memo + i }.should eq(16) } it "raises if empty" do - begin + expect_raises EmptyEnumerable do ([] of Int32).inject { |memo, i| memo + i } - fail "expected inject to raise" - rescue EmptyEnumerable end end end @@ -33,10 +31,8 @@ describe "Enumerable" do assert { [1, 2, 3].min.should eq(1) } it "raises if empty" do - begin + expect_raises EmptyEnumerable do ([] of Int32).min - fail "expected inject to raise" - rescue EmptyEnumerable end end end @@ -45,10 +41,8 @@ describe "Enumerable" do assert { [1, 2, 3].max.should eq(3) } it "raises if empty" do - begin + expect_raises EmptyEnumerable do ([] of Int32).max - fail "expected inject to raise" - rescue EmptyEnumerable end end end @@ -57,10 +51,8 @@ describe "Enumerable" do assert { [1, 2, 3].minmax.should eq({1, 3}) } it "raises if empty" do - begin + expect_raises EmptyEnumerable do ([] of Int32).minmax - fail "expected inject to raise" - rescue EmptyEnumerable end end end diff --git a/spec/std/file_spec.cr b/spec/std/file_spec.cr index 83ceea3e5ffbf2116ca92bd0e412393d58a20b0c..72f2854d34148cc6759dab1c8d4220f4f3e234ec 100755 --- a/spec/std/file_spec.cr +++ b/spec/std/file_spec.cr @@ -101,10 +101,8 @@ describe "File" do end it "gets stat for non-existent file and raises" do - begin + expect_raises Errno do File.stat("non-existent") - fail "expected Errno to be raised" - rescue Errno end end @@ -128,10 +126,8 @@ describe "File" do it "raises errno when file doesn't exist" do filename = "#{__DIR__}/data/temp1.txt" - begin + expect_raises Errno do File.delete(filename) - fail "expected Errno to be raised" - rescue Errno end end end @@ -150,10 +146,8 @@ describe "File" do it "raises if old file doesn't exist" do filename = "#{__DIR__}/data/temp1.txt" - begin + expect_raises Errno do File.rename(filename, "#{filename}.new") - fail "expected Errno to be raised" - rescue Errno end end end diff --git a/spec/std/hash_spec.cr b/spec/std/hash_spec.cr index 2dea546750364910a35da76be5b1ce9aff6b6e04..6ea2403f9b84619310bd289a1fc608a4b44b065f 100755 --- a/spec/std/hash_spec.cr +++ b/spec/std/hash_spec.cr @@ -109,10 +109,8 @@ describe "Hash" do it "fetches and raises" do a = {1 => 2} - begin + expect_raises Exception, "Missing hash value: 2" do a.fetch(2) - fail "expected fetch to raise" - rescue end end end diff --git a/spec/std/json/parser_spec.cr b/spec/std/json/parser_spec.cr index 62c46b2a8b957e5fb70f7fac4cb106fa9643a5d9..c342998920c64b14e58e24bfa33c9e2a6d0aca33 100644 --- a/spec/std/json/parser_spec.cr +++ b/spec/std/json/parser_spec.cr @@ -9,10 +9,8 @@ end def it_raises_on_parse_json(string) it "raises on parse #{string}" do - begin + expect_raises Json::ParseException do Json.parse(string) - fail "expected Json.parse to raise" - rescue Json::ParseException end end end diff --git a/spec/std/json/pull_parser_spec.cr b/spec/std/json/pull_parser_spec.cr index 0ec6c9774f77597bd1f8ad1162f0a745c203a540..9f1df382d6829593d05a276a9904f96edb90aedd 100644 --- a/spec/std/json/pull_parser_spec.cr +++ b/spec/std/json/pull_parser_spec.cr @@ -86,9 +86,9 @@ class Json::PullParser end def assert_error - read_next - fail "expected to raise" - rescue Json::ParseException + expect_raises Json::ParseException do + read_next + end end end @@ -102,13 +102,11 @@ end def assert_pull_parse_error(string) it "errors on #{string}" do - begin + expect_raises Json::ParseException do parser = Json::PullParser.new string while parser.kind != :EOF parser.read_next end - fail "expected to raise" - rescue Json::ParseException end end end diff --git a/spec/std/option_parser_spec.cr b/spec/std/option_parser_spec.cr index f19293d443fe771c96343dadff15231c39079964..97c646cbdc3036f5647805cb05ed9ac51308aa3e 100755 --- a/spec/std/option_parser_spec.cr +++ b/spec/std/option_parser_spec.cr @@ -25,22 +25,21 @@ describe "OptionParser" do end def expect_missing_option(option) - OptionParser.parse([] of String) do |opts| - opts.on(option, "some flag") do |flag_value| + expect_raises OptionParser::MissingOption do + OptionParser.parse([] of String) do |opts| + opts.on(option, "some flag") do |flag_value| + end end end - fail "expected OptionParser::MissingOption to be raised" - rescue ex : OptionParser::MissingOption end def expect_missing_option(args, option, flag) - OptionParser.parse(args) do |opts| - opts.on(option, "some flag") do |flag_value| + expect_raises OptionParser::MissingOption, "Missing option: #{flag}" do + OptionParser.parse(args) do |opts| + opts.on(option, "some flag") do |flag_value| + end end end - fail "expected OptionParser::MissingOption to be raised" - rescue ex : OptionParser::MissingOption - ex.message.should eq("Missing option: #{flag}") end it "has flag" do @@ -155,13 +154,10 @@ describe "OptionParser" do end it "raises on invalid option" do - begin + expect_raises OptionParser::InvalidOption, "Invalid option: -j" do OptionParser.parse(["-f", "-j"]) do |opts| opts.on("-f", "some flag") { } end - fail "Expected to raise OptionParser::InvalidOption" - rescue ex : OptionParser::InvalidOption - ex.message.should eq("Invalid option: -j") end end diff --git a/spec/std/random_spec.cr b/spec/std/random_spec.cr index 59a41c2f7a8a8f2685dc6d1840a2506a65bcd15b..88a1cc766e03fcecd7af04622fe5f118beecc3bd 100755 --- a/spec/std/random_spec.cr +++ b/spec/std/random_spec.cr @@ -17,11 +17,8 @@ describe "Random" do end it "raises on invalid number" do - begin + expect_raises ArgumentError, "incorrect rand value: 0" do rand(0) - fail "expect rand(0) to raise" - rescue ex - ex.message.should eq("incorrect rand value: 0") end end @@ -40,11 +37,8 @@ describe "Random" do end it "raises on invalid range" do - begin + expect_raises ArgumentError, "incorrect rand value: 1...1" do rand(1...1) - fail "expect rand(1...1) to raise" - rescue ex - ex.message.should eq("incorrect rand value: 1...1") end end end diff --git a/spec/std/regexp_spec.cr b/spec/std/regexp_spec.cr index fb85c246c3ffa467bec40505385f4afaebcf9b8a..97e76ee7d7c4b57bffeb360b13892ccaad309727 100755 --- a/spec/std/regexp_spec.cr +++ b/spec/std/regexp_spec.cr @@ -19,19 +19,15 @@ describe "Regex" do it "raises if outside match range with []" do "foo" =~ /foo/ - begin + expect_raises IndexOutOfBounds do $1 - fail "Expected $1 to raise" - rescue ex : IndexOutOfBounds end end it "raises if outside match range with begin" do "foo" =~ /foo/ - begin + expect_raises IndexOutOfBounds do $1 - fail "Expected $1 to raise" - rescue ex : IndexOutOfBounds end end diff --git a/src/random.cr b/src/random.cr index 83a528c7f40b4f803818a8612ac03b046dcb99f2..3297377a4522a0ba0523af588f4fa4e0b0feaf42 100644 --- a/src/random.cr +++ b/src/random.cr @@ -21,7 +21,7 @@ def rand(x : Int) if x > 0 C.rand % x else - raise "incorrect rand value: #{x}" + raise ArgumentError.new "incorrect rand value: #{x}" end end @@ -31,6 +31,6 @@ def rand(x : Range(Int32, Int32)) if span > 0 x.begin + rand(span) else - raise "incorrect rand value: #{x}" + raise ArgumentError.new "incorrect rand value: #{x}" end end diff --git a/src/spec.cr b/src/spec.cr index f3f81cd1397fb815552c745a32180552e62bb4f5..c9885c7911c9ed7c64aac9893b4a35e1f520ad27 100644 --- a/src/spec.cr +++ b/src/spec.cr @@ -226,7 +226,15 @@ def fail(msg) raise Spec::AssertionFailed.new(msg) end -macro expect_raise(klass) +macro expect_raises + begin + {{yield}} + fail "expected to raise" + rescue + end +end + +macro expect_raises(klass) begin {{yield}} fail "expected to raise {{klass.id}}" @@ -234,6 +242,26 @@ macro expect_raise(klass) end end +macro expect_raises(klass, message) + begin + {{yield}} + fail "expected to raise {{klass.id}}" + rescue _ex_ : {{klass.id}} + _msg_ = {{message}} + _ex_to_s_ = _ex_.to_s + case _msg_ + when Regex + unless (_ex_to_s_ =~ _msg_) + fail "expected {{klass.id}}'s message to match #{_msg_}, but was #{_ex_to_s_.inspect}" + end + when String + unless _ex_to_s_.includes?(_msg_) + fail "expected {{klass.id}}'s message to include #{_msg_.inspect}, but was #{_ex_to_s_.inspect}" + end + end + end +end + class Object def should(expectation) unless expectation.match self