From c55dca2e3c63daf7fd447bfeed93106f45649b51 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig <aborenszweig@manas.com.ar> Date: Wed, 9 Jul 2014 23:26:57 -0300 Subject: [PATCH] Added expect_raises macros and use them in specs. Also make assert_syntax_error create a spec with "it" (more concise) --- spec/compiler/lexer/lexer_spec.cr | 79 +++----- spec/compiler/parser/parser_spec.cr | 172 +++++------------- spec/compiler/type_inference/block_spec.cr | 6 +- .../compiler/type_inference/exception_spec.cr | 20 +- spec/compiler/type_inference/fun_spec.cr | 6 +- spec/compiler/type_inference/var_spec.cr | 11 +- spec/spec_helper.cr | 41 +++-- spec/std/array_spec.cr | 50 ++--- spec/std/bit_array_spec.cr | 4 +- spec/std/cast_spec.cr | 15 +- spec/std/char_reader_spec.cr | 6 +- spec/std/dir_spec.cr | 18 +- spec/std/enumerable_spec.cr | 16 +- spec/std/file_spec.cr | 12 +- spec/std/hash_spec.cr | 4 +- spec/std/json/parser_spec.cr | 4 +- spec/std/json/pull_parser_spec.cr | 10 +- spec/std/option_parser_spec.cr | 22 +-- spec/std/random_spec.cr | 10 +- spec/std/regexp_spec.cr | 8 +- src/random.cr | 4 +- src/spec.cr | 30 ++- 22 files changed, 195 insertions(+), 353 deletions(-) diff --git a/spec/compiler/lexer/lexer_spec.cr b/spec/compiler/lexer/lexer_spec.cr index 1553982738..c21d2f5df7 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 709c62a08c..1c2e028401 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 19cabc3807..24bca74569 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 8923fd2396..10a4af87d4 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 8745370e15..f7272fa060 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 c8f8c44b79..a5ee9c3e2a 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 41ceeabf00..15873697d1 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 48ae29838f..79d615eccd 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 aadfafdef3..01674c9f67 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 d3131cfb69..0baaa73cec 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 c4cabf6464..ac955a1091 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 f3ba9d6b0c..5cb6d672bb 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 8ed37eab26..c532091a2d 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 83ceea3e5f..72f2854d34 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 2dea546750..6ea2403f9b 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 62c46b2a8b..c342998920 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 0ec6c9774f..9f1df382d6 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 f19293d443..97c646cbdc 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 59a41c2f7a..88a1cc766e 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 fb85c246c3..97e76ee7d7 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 83a528c7f4..3297377a45 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 f3f81cd139..c9885c7911 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 -- GitLab