From 3164cf8f12f14b725b918e3170bb0a9085af8298 Mon Sep 17 00:00:00 2001 From: Yegappan Lakshmanan Date: Thu, 28 Mar 2024 10:36:42 +0100 Subject: patch 9.1.0219: Vim9: No enum support Problem: No enum support Solution: Implement enums for Vim9 script (Yegappan Lakshmanan) closes: #14224 Signed-off-by: Yegappan Lakshmanan Signed-off-by: Christian Brabandt --- src/testdir/Make_all.mak | 2 + src/testdir/test_vim9_class.vim | 43 ++ src/testdir/test_vim9_enum.vim | 1476 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 1521 insertions(+) create mode 100644 src/testdir/test_vim9_enum.vim (limited to 'src/testdir') diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak index c4403e67ae..ab4d42a67c 100644 --- a/src/testdir/Make_all.mak +++ b/src/testdir/Make_all.mak @@ -40,6 +40,7 @@ TEST_VIM9 = \ test_vim9_class \ test_vim9_cmd \ test_vim9_disassemble \ + test_vim9_enum \ test_vim9_expr \ test_vim9_fails \ test_vim9_func \ @@ -53,6 +54,7 @@ TEST_VIM9_RES = \ test_vim9_class.res \ test_vim9_cmd.res \ test_vim9_disassemble.res \ + test_vim9_enum.res \ test_vim9_expr.res \ test_vim9_fails.res \ test_vim9_func.res \ diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim index d6c55bfffa..f0c6f0cd00 100644 --- a/src/testdir/test_vim9_class.vim +++ b/src/testdir/test_vim9_class.vim @@ -2275,6 +2275,18 @@ def Test_interface_basics() v9.CheckScriptSuccess(lines) enddef +" Test for using string() with an interface +def Test_interface_to_string() + var lines =<< trim END + vim9script + interface Intf + def Method(nr: number) + endinterface + assert_equal("interface Intf", string(Intf)) + END + v9.CheckSourceSuccess(lines) +enddef + def Test_class_implements_interface() var lines =<< trim END vim9script @@ -10391,6 +10403,23 @@ def Test_compound_op_in_objmethod_lambda() v9.CheckScriptSuccess(lines) enddef +" Test for using test_refcount() with a class and an object +def Test_class_object_refcount() + var lines =<< trim END + vim9script + class A + endclass + var a: A = A.new() + assert_equal(2, test_refcount(A)) + assert_equal(1, test_refcount(a)) + var b = a + assert_equal(2, test_refcount(A)) + assert_equal(2, test_refcount(a)) + assert_equal(2, test_refcount(b)) + END + v9.CheckScriptSuccess(lines) +enddef + " call a lambda function in one object from another object def Test_lambda_invocation_across_classes() var lines =<< trim END @@ -10420,4 +10449,18 @@ def Test_lambda_invocation_across_classes() v9.CheckScriptSuccess(lines) enddef +" Test for using a class member which is an object of the current class +def Test_current_class_object_class_member() + var lines =<< trim END + vim9script + class A + public static var obj1: A = A.new(10) + var n: number + endclass + defcompile + assert_equal(10, A.obj1.n) + END + v9.CheckScriptSuccess(lines) +enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/testdir/test_vim9_enum.vim b/src/testdir/test_vim9_enum.vim new file mode 100644 index 0000000000..6e10e0c705 --- /dev/null +++ b/src/testdir/test_vim9_enum.vim @@ -0,0 +1,1476 @@ +" Test Vim9 enums + +source check.vim +import './vim9.vim' as v9 + +" Test for parsing an enum definition +def Test_enum_parse() + # enum supported only in a Vim9 script + var lines =<< trim END + enum Foo + endenum + END + v9.CheckSourceFailure(lines, 'E1414: Enum can only be defined in Vim9 script', 1) + + # First character in an enum name should be capitalized. + lines =<< trim END + vim9script + enum foo + endenum + END + v9.CheckSourceFailure(lines, 'E1415: Enum name must start with an uppercase letter: foo', 2) + + # Only alphanumeric characters are supported in an enum name + lines =<< trim END + vim9script + enum Foo@bar + endenum + END + v9.CheckSourceFailure(lines, 'E1315: White space required after name: Foo@bar', 2) + + # Unsupported keyword (instead of enum) + lines =<< trim END + vim9script + noenum Something + endenum + END + v9.CheckSourceFailure(lines, 'E492: Not an editor command: noenum Something', 2) + + # Only the complete word "enum" should be recognized + lines =<< trim END + vim9script + enums Something + endenum + END + v9.CheckSourceFailure(lines, 'E492: Not an editor command: enums Something', 2) + + # The complete "endenum" should be specified. + lines =<< trim END + vim9script + enum Something + enden + END + v9.CheckSourceFailure(lines, 'E1065: Command cannot be shortened: enden', 3) + + # Only the complete word "endenum" should be recognized + lines =<< trim END + vim9script + enum Something + endenums + END + v9.CheckSourceFailure(lines, 'E1420: Missing :endenum', 4) + + # all lower case should be used for "enum" + lines =<< trim END + vim9script + Enum Something + endenum + END + v9.CheckSourceFailure(lines, 'E492: Not an editor command: Enum Something', 2) + + # all lower case should be used for "endenum" + lines =<< trim END + vim9script + enum Something + Endenum + END + v9.CheckSourceFailure(lines, 'E1420: Missing :endenum', 4) + + # Additional words after "endenum" + lines =<< trim END + vim9script + enum Something + endenum school's out + END + v9.CheckSourceFailure(lines, "E488: Trailing characters: school's out", 3) + + # Additional commands after "endenum" + lines =<< trim END + vim9script + enum Something + endenum | echo 'done' + END + v9.CheckSourceFailure(lines, "E488: Trailing characters: | echo 'done'", 3) + + # Try to define enum in a single command + lines =<< trim END + vim9script + enum Something | endenum + END + v9.CheckSourceFailure(lines, 'E1420: Missing :endenum', 3) + + # Try to define an enum with the same name as an existing variable + lines =<< trim END + vim9script + var Something: list = [1] + enum Something + endenum + END + v9.CheckSourceFailure(lines, 'E1041: Redefining script item: "Something"', 3) + + # Unsupported special character following enum name + lines =<< trim END + vim9script + enum Foo + first, + second : 20 + endenum + END + v9.CheckSourceFailure(lines, 'E1123: Missing comma before argument: : 20', 4) + + # Try initializing an enum item with a number + lines =<< trim END + vim9script + enum Foo + first, + second = 2 + endenum + END + v9.CheckSourceFailure(lines, 'E1123: Missing comma before argument: = 2', 4) + + # Try initializing an enum item with a String + lines =<< trim END + vim9script + enum Foo + first, + second = 'second' + endenum + defcompile + END + v9.CheckSourceFailure(lines, "E1123: Missing comma before argument: = 'second'", 4) + + # Try initializing an enum item with a List + lines =<< trim END + vim9script + enum Foo + first, + second = [] + endenum + END + v9.CheckSourceFailure(lines, 'E1123: Missing comma before argument: = []', 4) + + # Use a colon after name + lines =<< trim END + vim9script + enum Foo + + # first + first: + second + endenum + END + v9.CheckSourceFailure(lines, 'E1123: Missing comma before argument: :', 5) + + # Use a '==' + lines =<< trim END + vim9script + enum Foo + first == 1 + endenum + defcompile + END + v9.CheckSourceFailure(lines, 'E1123: Missing comma before argument: == 1', 3) + + # Missing comma after an enum item + lines =<< trim END + vim9script + enum Planet + mercury + venus + endenum + END + v9.CheckSourceFailure(lines, 'E1419: Not a valid command in an Enum: venus', 4) + + # Comma at the beginning of an item + lines =<< trim END + vim9script + enum Planet + mercury + ,venus + endenum + END + v9.CheckSourceFailure(lines, 'E1419: Not a valid command in an Enum: ,venus', 4) + # Space before comma + lines =<< trim END + vim9script + enum Planet + mercury , + venus + endenum + END + v9.CheckSourceFailure(lines, "E1068: No white space allowed before ','", 3) + + # No space after comma + lines =<< trim END + vim9script + enum Planet + mercury,venus + endenum + END + v9.CheckSourceFailure(lines, "E1069: White space required after ',': mercury,venus", 3) + + # no comma between items in the same line + lines =<< trim END + vim9script + enum Planet + mercury venus earth + endenum + defcompile + END + v9.CheckSourceFailure(lines, 'E1123: Missing comma before argument: venus earth', 3) + + # No space after an item and comment between items + lines =<< trim END + vim9script + enum Planet + mercury + + # Venus + venus + endenum + END + v9.CheckSourceFailure(lines, 'E1419: Not a valid command in an Enum: venus', 6) + + # Comma is supported for the last item + lines =<< trim END + vim9script + enum Planet + mercury, + venus, + endenum + var p: Planet + p = Planet.mercury + p = Planet.venus + END + v9.CheckSourceSuccess(lines) + + # invalid enum value declaration + lines =<< trim END + vim9script + enum Fruit + Apple, + $%@ + endenum + defcompile + END + v9.CheckSourceFailure(lines, 'E1418: Invalid enum value declaration: $%@', 4) + + # Duplicate enum value + lines =<< trim END + vim9script + enum A + Foo, + Bar, + Foo + endenum + END + v9.CheckSourceFailure(lines, 'E1428: Duplicate enum value: Foo', 5) + + # Duplicate enum value in the same line + lines =<< trim END + vim9script + enum A + Foo, Bar, Foo, + Bar + endenum + END + v9.CheckSourceFailure(lines, 'E1428: Duplicate enum value: Foo', 3) + + # Try extending a class when defining an enum + lines =<< trim END + vim9script + class Foo + endclass + enum Bar extends Foo + endenum + END + v9.CheckSourceFailure(lines, 'E1416: Enum cannot extend a class or enum', 4) + + # Try extending an enum + lines =<< trim END + vim9script + enum Foo + endenum + enum Bar extends Foo + endenum + END + v9.CheckSourceFailure(lines, 'E1416: Enum cannot extend a class or enum', 4) + + # Try extending an enum using a class + lines =<< trim END + vim9script + enum Foo + endenum + class Bar extends Foo + endclass + END + v9.CheckSourceFailure(lines, 'E1354: Cannot extend Foo', 5) + + # Try implementing an enum using a class + lines =<< trim END + vim9script + enum Foo + endenum + class Bar implements Foo + endclass + END + v9.CheckSourceFailure(lines, 'E1347: Not a valid interface: Foo', 5) + + # abstract method is not supported in an enum + lines =<< trim END + vim9script + enum Foo + Apple + abstract def Bar() + endenum + END + v9.CheckSourceFailure(lines, 'E1417: Abstract cannot be used in an Enum', 4) + + # Define an enum without any enum values but only with an object variable + lines =<< trim END + vim9script + enum Foo + final n: number = 10 + endenum + END + v9.CheckSourceFailure(lines, 'E1123: Missing comma before argument: n: number = 10', 3) +enddef + +def Test_basic_enum() + # Declare a simple enum + var lines =<< trim END + vim9script + enum Foo + apple, + orange + endenum + var a: Foo = Foo.apple + var b: Foo = Foo.orange + assert_equal(a, Foo.apple) + assert_equal(b, Foo.orange) + END + v9.CheckSourceSuccess(lines) + + # Multiple enums in a single line + lines =<< trim END + vim9script + enum Foo + apple, orange + endenum + assert_equal('enum', typename(Foo.apple)) + assert_equal('enum', typename(Foo.orange)) + END + v9.CheckSourceSuccess(lines) + + # Comments and empty lines are supported between enum items + lines =<< trim END + vim9script + enum Foo + # Apple + apple, + + # Orange + orange + endenum + def Fn() + var a: Foo = Foo.apple + var b: Foo = Foo.orange + assert_equal(a, Foo.apple) + assert_equal(b, Foo.orange) + enddef + END + v9.CheckSourceSuccess(lines) + + # Try using a non-existing enum value + lines =<< trim END + vim9script + enum Foo + apple, + orange + endenum + var a: Foo = Foo.pear + END + v9.CheckSourceFailure(lines, 'E1422: Enum value "pear" not found in enum "Foo"', 6) + + # Enum function argument + lines =<< trim END + vim9script + enum Foo + apple, + orange + endenum + def Fn(a: Foo): Foo + return a + enddef + assert_equal(Foo.apple, Fn(Foo.apple)) + END + v9.CheckSourceSuccess(lines) + + # Enum function argument + lines =<< trim END + vim9script + enum Foo + apple, + orange + endenum + def Fn(a: Foo): Foo + return a + enddef + Fn({}) + END + v9.CheckSourceFailure(lines, 'E1013: Argument 1: type mismatch, expected enum but got dict', 9) + + # Returning an enum in a function returning number + lines =<< trim END + vim9script + enum Foo + apple, + orange + endenum + def Fn(): number + return Foo.orange + enddef + Fn() + END + v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected number but got enum', 1) + + # Returning a number in a function returning enum + lines =<< trim END + vim9script + enum Foo + apple, + orange + endenum + def Fn(): Foo + return 20 + enddef + Fn() + END + v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected enum but got number', 1) + + # Use a List of enums + lines =<< trim END + vim9script + enum Planet + Mercury, + Venus, + Earth + endenum + var l1: list = [Planet.Mercury, Planet.Venus] + assert_equal(Planet.Venus, l1[1]) + def Fn() + var l2: list = [Planet.Mercury, Planet.Venus] + assert_equal(Planet.Venus, l2[1]) + enddef + END + v9.CheckSourceSuccess(lines) + + # Try using an enum as a value + lines =<< trim END + vim9script + enum Fruit + Apple, + Orange + endenum + var a = Fruit + END + v9.CheckSourceFailure(lines, 'E1421: Enum "Fruit" cannot be used as a value', 6) +enddef + +" Test for type() and typename() of an enum +def Test_enum_type() + var lines =<< trim END + vim9script + enum Fruit + Apple, + Orange + endenum + assert_equal('enum', typename(Fruit)) + assert_equal('enum', typename(Fruit.Apple)) + assert_equal(v:t_enum, type(Fruit)) + assert_equal(v:t_enumvalue, type(Fruit.Apple)) + assert_equal(15, type(Fruit)) + assert_equal(16, type(Fruit.Apple)) + END + v9.CheckSourceSuccess(lines) + + # Assign an enum to a variable with any type + lines =<< trim END + vim9script + enum Fruit + Apple, + Orange + endenum + var a = Fruit.Apple + var b: any = Fruit.Orange + assert_equal('enum', typename(a)) + assert_equal('enum', typename(b)) + END + v9.CheckSourceSuccess(lines) +enddef + +" Try modifying an enum or an enum item +def Test_enum_modify() + # Try assigning an unsupported value to an enum + var lines =<< trim END + vim9script + enum Foo + apple + endenum + var a: Foo = 30 + END + v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected enum but got number', 5) + + # Try assigning an unsupported value to an enum in a function + lines =<< trim END + vim9script + enum Foo + apple + endenum + def Fn() + var a: Foo = 30 + enddef + defcompile + END + v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected enum but got number', 1) + + # Try assigning a number to an enum + lines =<< trim END + vim9script + enum Foo + apple, + orange + endenum + Foo = 10 + END + v9.CheckSourceFailure(lines, 'E1421: Enum "Foo" cannot be used as a value', 6) + + # Try assigning a number to an enum in a function + lines =<< trim END + vim9script + enum Foo + apple + endenum + def Fn() + Foo = 10 + enddef + defcompile + END + v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected enum but got number', 1) + + # Try assigning a number to an enum value + lines =<< trim END + vim9script + enum Foo + apple + endenum + Foo.apple = 20 + END + v9.CheckSourceFailure(lines, 'E1423: Enum value "Foo.apple" cannot be modified', 5) + + # Try assigning a number to an enum value in a function + lines =<< trim END + vim9script + enum Foo + apple + endenum + def Fn() + Foo.apple = 20 + enddef + defcompile + END + v9.CheckSourceFailure(lines, 'E1423: Enum value "Foo.apple" cannot be modified', 1) + + # Try assigning one enum to another + lines =<< trim END + vim9script + enum Foo + endenum + enum Bar + endenum + Foo = Bar + END + v9.CheckSourceFailure(lines, 'E1421: Enum "Bar" cannot be used as a value', 6) + + # Try assigning one enum to another in a function + lines =<< trim END + vim9script + enum Foo + endenum + enum Bar + endenum + def Fn() + Foo = Bar + enddef + defcompile + END + v9.CheckSourceFailure(lines, 'E1421: Enum "Bar" cannot be used as a value', 1) + + # Try assigning one enum item to another enum item + lines =<< trim END + vim9script + enum Foo + Apple + endenum + enum Bar + Orange + endenum + Foo.Apple = Bar.Orange + END + v9.CheckSourceFailure(lines, 'E1423: Enum value "Foo.Apple" cannot be modified', 8) + + # Try assigning one enum item to another enum item in a function + lines =<< trim END + vim9script + enum Foo + Apple + endenum + enum Bar + Orange + endenum + def Fn() + Foo.Apple = Bar.Orange + enddef + defcompile + END + v9.CheckSourceFailure(lines, 'E1423: Enum value "Foo.Apple" cannot be modified', 1) +enddef + +" Test for using enum in an expression +def Test_enum_expr() + var lines =<< trim END + vim9script + enum Color + Red, Blue, Green + endenum + var a: number = 1 + Color + END + v9.CheckSourceFailure(lines, 'E1421: Enum "Color" cannot be used as a value', 5) + + lines =<< trim END + vim9script + enum Color + Red, Blue, Green + endenum + var a: number = 1 + Color.Red + END + v9.CheckSourceFailure(lines, 'E1424: Using an Enum "Color" as a Number', 5) + + lines =<< trim END + vim9script + enum Color + Red, Blue, Green + endenum + var s: string = "abc" .. Color + END + v9.CheckSourceFailure(lines, 'E1421: Enum "Color" cannot be used as a value', 5) + + lines =<< trim END + vim9script + enum Color + Red, Blue, Green + endenum + var s: string = "abc" .. Color.Red + END + v9.CheckSourceFailure(lines, 'E1425: Using an Enum "Color" as a String', 5) +enddef + +" Using an enum in a lambda function +def Test_enum_lambda() + var lines =<< trim END + vim9script + enum Planet + Mercury, + Venus, + Earth, + endenum + var Fn = (p: Planet): Planet => p + for [idx, v] in items([Planet.Mercury, Planet.Venus, Planet.Earth]) + assert_equal(idx, Fn(v).ordinal) + endfor + END + v9.CheckSourceSuccess(lines) +enddef + +" Comparison using enums +def Test_enum_compare() + var lines =<< trim END + vim9script + enum Planet + Mercury, + Venus, + Earth, + endenum + enum Fruit + Apple, + Orange + endenum + + var p: Planet = Planet.Venus + var f: Fruit = Fruit.Orange + assert_equal(true, p == Planet.Venus) + assert_equal(false, p == Planet.Earth) + assert_equal(false, p == f) + assert_equal(true, Planet.Mercury == Planet.Mercury) + assert_equal(true, Planet.Venus != Planet.Earth) + assert_equal(true, Planet.Mercury != Fruit.Apple) + + def Fn1() + var p2: Planet = Planet.Venus + var f2: Fruit = Fruit.Orange + assert_equal(true, p2 == Planet.Venus) + assert_equal(false, p2 == Planet.Earth) + assert_equal(false, p2 == f2) + enddef + Fn1() + + # comparison using "is" and "isnot" + assert_equal(true, p is Planet.Venus) + assert_equal(true, p isnot Planet.Earth) + assert_equal(false, p is Fruit.Orange) + assert_equal(true, p isnot Fruit.Orange) + def Fn2(arg: Planet) + assert_equal(true, arg is Planet.Venus) + assert_equal(true, arg isnot Planet.Earth) + assert_equal(false, arg is Fruit.Orange) + assert_equal(true, arg isnot Fruit.Orange) + enddef + Fn2(p) + + class A + endclass + var o: A = A.new() + assert_equal(false, p == o) + END + v9.CheckSourceSuccess(lines) +enddef + +" Test for using an enum as a default argument to a function +def Test_enum_default_arg() + var lines =<< trim END + vim9script + enum Day + Monday, Tuesday, Wednesday + endenum + def Fn(d: Day = Day.Tuesday): Day + return d + enddef + assert_equal(Day.Tuesday, Fn()) + assert_equal(Day.Wednesday, Fn(Day.Wednesday)) + END + v9.CheckSourceSuccess(lines) +enddef + +" Test for enum garbage collection +func Test_enum_garbagecollect() + let lines =<< trim END + vim9script + enum Car + Honda, Ford, Tesla + endenum + assert_equal(1, Car.Ford.ordinal) + call test_garbagecollect_now() + assert_equal(1, Car.Ford.ordinal) + var c: Car = Car.Tesla + assert_equal(2, c.ordinal) + call test_garbagecollect_now() + assert_equal(2, c.ordinal) + END + call v9.CheckSourceSuccess(lines) + + " garbage collection with a variable of type any + let lines =<< trim END + vim9script + enum Car + Honda, Ford, Tesla + endenum + call test_garbagecollect_now() + var c: any = Car.Tesla + call test_garbagecollect_now() + assert_equal(Car.Tesla, c) + END + call v9.CheckSourceSuccess(lines) + + " garbage collection with function arguments and return types + let lines =<< trim END + vim9script + enum Car + Honda, Ford, Tesla + endenum + def Fn(a: Car): Car + assert_equal(Car.Ford, a) + return Car.Tesla + enddef + call test_garbagecollect_now() + var b: Car = Car.Ford + call test_garbagecollect_now() + assert_equal(Car.Tesla, Fn(b)) + call test_garbagecollect_now() + END + call v9.CheckSourceSuccess(lines) +endfunc + +" Test for the enum values class variable +def Test_enum_values() + var lines =<< trim END + vim9script + enum Car + Honda, Ford, Tesla + endenum + var l: list = Car.values + assert_equal(Car.Ford, l[1]) + END + v9.CheckSourceSuccess(lines) + + # empty enum + lines =<< trim END + vim9script + enum Car + endenum + assert_equal([], Car.values) + END + v9.CheckSourceSuccess(lines) + + # single value + lines =<< trim END + vim9script + enum Car + Honda + endenum + assert_equal([Car.Honda], Car.values) + END + v9.CheckSourceSuccess(lines) + + lines =<< trim END + vim9script + enum A + Red, + Blue + static def GetValues(): list + return values + enddef + endenum + assert_equal([A.Red, A.Blue], A.GetValues()) + END + v9.CheckSourceSuccess(lines) + + # Other class variables in an enum should not be added to 'values' + lines =<< trim END + vim9script + enum LogLevel + Error, Warn + static const x: number = 22 + endenum + assert_equal([LogLevel.Error, LogLevel.Warn], LogLevel.values) + END + v9.CheckSourceSuccess(lines) + + # Other class variable of enum type should not be added to 'values' + lines =<< trim END + vim9script + enum LogLevel + Error, Warn + static const x: LogLevel = LogLevel.Warn + endenum + assert_equal([LogLevel.Error, LogLevel.Warn], LogLevel.values) + END + v9.CheckSourceSuccess(lines) +enddef + +" Test comments in enums +def Test_enum_comments() + var lines =<< trim END + vim9script + enum Car # cars + # before enum + Honda, # honda + # before enum + Ford # ford + endenum + assert_equal(1, Car.Ford.ordinal) + END + v9.CheckSourceSuccess(lines) + + # Test for using an unsupported comment + lines =<< trim END + vim9script + enum Car + Honda, + Ford, + #{ + endenum + defcompile + END + v9.CheckSourceFailure(lines, 'E1170: Cannot use #{ to start a comment', 4) +enddef + +" Test string() with enums +def Test_enum_string() + var lines =<< trim END + vim9script + enum Car + Honda, + Ford + endenum + assert_equal("enum Car", string(Car)) + assert_equal("Car.Honda", string(Car.Honda)) + END + v9.CheckSourceSuccess(lines) +enddef + +" Test for importing an enum +def Test_enum_import() + var lines =<< trim END + vim9script + export enum Star + Gemini, + Orion, + Pisces + endenum + END + writefile(lines, 'Xenumexport.vim', 'D') + + lines =<< trim END + vim9script + import './Xenumexport.vim' as mod + + var s1: mod.Star = mod.Star.Orion + assert_equal(true, s1 == mod.Star.Orion) + assert_equal(2, mod.Star.Pisces.ordinal) + var l1: list = mod.Star.values + assert_equal("Star.Orion", string(l1[1])) + assert_equal(s1, l1[1]) + + def Fn() + var s2: mod.Star = mod.Star.Orion + assert_equal(true, s2 == mod.Star.Orion) + assert_equal(2, mod.Star.Pisces.ordinal) + var l2: list = mod.Star.values + assert_equal("Star.Orion", string(l2[1])) + assert_equal(s2, l2[1]) + enddef + Fn() + END + v9.CheckScriptSuccess(lines) +enddef + +" Test for using test_refcount() with enum +def Test_enum_refcount() + var lines =<< trim END + vim9script + enum Foo + endenum + assert_equal(1, test_refcount(Foo)) + + enum Star + Gemini, + Orion, + endenum + assert_equal(3, test_refcount(Star)) + assert_equal(2, test_refcount(Star.Gemini)) + assert_equal(2, test_refcount(Star.Orion)) + + var s: Star + assert_equal(3, test_refcount(Star)) + assert_equal(-1, test_refcount(s)) + s = Star.Orion + assert_equal(3, test_refcount(Star)) + assert_equal(3, test_refcount(s)) + assert_equal(2, test_refcount(Star.Gemini)) + var t = s + assert_equal(3, test_refcount(Star)) + assert_equal(4, test_refcount(s)) + assert_equal(4, test_refcount(Star.Orion)) + END + v9.CheckSourceSuccess(lines) +enddef + +" Test for defining an enum with additional object variables and methods +def Test_enum_enhanced() + var lines =<< trim END + vim9script + enum Vehicle + car(4, 5, 400), + bus(6, 50, 800), + bicycle(2, 1, 0) + + final tires: number + final passengers: number + final carbonPerKilometer: number + + def new(t: number, p: number, cpk: number) + this.tires = t + this.passengers = p + this.carbonPerKilometer = cpk + enddef + + def CarbonFootprint(): float + return round(this.carbonPerKilometer / this.passengers) + enddef + + def IsTwoWheeled(): bool + return this == Vehicle.bicycle + enddef + + def CompareTo(other: Vehicle): float + return this.CarbonFootprint() - other.CarbonFootprint() + enddef + endenum + + var v: Vehicle = Vehicle.bus + assert_equal([6, 50, 800], [v.tires, v.passengers, v.carbonPerKilometer]) + assert_equal(true, Vehicle.bicycle.IsTwoWheeled()) + assert_equal(false, Vehicle.car.IsTwoWheeled()) + assert_equal(16.0, Vehicle.bus.CarbonFootprint()) + END + v9.CheckSourceSuccess(lines) +enddef + +" Test for the enum value 'name' variable +def Test_enum_name() + # Check the names of enum values + var lines =<< trim END + vim9script + enum Planet + Mercury, + Venus, + Earth + endenum + assert_equal('Mercury', Planet.Mercury.name) + assert_equal('Venus', Planet.Venus.name) + assert_equal('Earth', Planet.Earth.name) + assert_equal('string', typename(Planet.Earth.name)) + END + v9.CheckSourceSuccess(lines) + + # Check the name of enum items in the constructor + lines =<< trim END + vim9script + enum Planet + Mercury("Mercury"), + Venus("Venus"), + Earth("Earth") + + def new(s: string) + assert_equal(s, this.name) + enddef + endenum + defcompile + END + v9.CheckSourceSuccess(lines) + + # Try assigning to the name of an enum + lines =<< trim END + vim9script + enum Fruit + Apple + endenum + Fruit.Apple.name = 'foo' + END + v9.CheckSourceFailure(lines, 'E1335: Variable "name" in class "Fruit" is not writable', 5) + + # Try assigning to the name of an enum in a function + lines =<< trim END + vim9script + enum Fruit + Apple + endenum + def Fn() + Fruit.Apple.name = 'bar' + enddef + defcompile + END + v9.CheckSourceFailure(lines, 'E1423: Enum value "Fruit.name" cannot be modified', 1) + + # Try to overwrite an enum value name in the enum constructor + lines =<< trim END + vim9script + enum Planet + Mercury, + Venus + + def new() + this.name = 'foo' + enddef + endenum + END + v9.CheckSourceFailure(lines, 'E1427: Enum "Planet" name cannot be modified', 1) + + # Try to declare an object variable named 'name' + lines =<< trim END + vim9script + enum Planet + Mercury + var name: string + endenum + END + v9.CheckSourceFailure(lines, 'E1369: Duplicate variable: name', 4) +enddef + +" Test for the enum value 'ordinal' variable +def Test_enum_ordinal() + # Check the ordinal values of enum items + var lines =<< trim END + vim9script + enum Planet + Mercury, + Venus, + Earth + endenum + assert_equal(0, Planet.Mercury.ordinal) + assert_equal(1, Planet.Venus.ordinal) + assert_equal(2, Planet.Earth.ordinal) + assert_equal('number', typename(Planet.Earth.ordinal)) + END + v9.CheckSourceSuccess(lines) + + # Check the ordinal value of enum items in the constructor + lines =<< trim END + vim9script + enum Planet + Mercury(0), + Venus(1), + Earth(2) + + def new(v: number) + assert_equal(v, this.ordinal) + enddef + endenum + defcompile + END + v9.CheckSourceSuccess(lines) + + # Try assigning to the ordinal value of an enum + lines =<< trim END + vim9script + enum Fruit + Apple + endenum + Fruit.Apple.ordinal = 20 + END + v9.CheckSourceFailure(lines, 'E1335: Variable "ordinal" in class "Fruit" is not writable', 5) + + # Try assigning to the ordinal value of an enum in a function + lines =<< trim END + vim9script + enum Fruit + Apple + endenum + def Fn() + Fruit.Apple.ordinal = 20 + enddef + defcompile + END + v9.CheckSourceFailure(lines, 'E1423: Enum value "Fruit.ordinal" cannot be modified', 1) + + # Try to overwrite an enum value ordinal in the enum constructor + lines =<< trim END + vim9script + enum Planet + Mercury, + Venus + + def new() + this.ordinal = 20 + enddef + endenum + END + v9.CheckSourceFailure(lines, 'E1426: Enum "Planet" ordinal value cannot be modified', 1) + + # Try to declare an object variable named 'ordinal' + lines =<< trim END + vim9script + enum Planet + Mercury + var ordinal: number + endenum + END + v9.CheckSourceFailure(lines, 'E1369: Duplicate variable: ordinal', 4) +enddef + +" Test for trying to create a new enum object using the constructor +def Test_enum_invoke_constructor() + var lines =<< trim END + vim9script + enum Foo + endenum + var f: Foo = Foo.new() + END + v9.CheckSourceFailure(lines, 'E1325: Method "new" not found in class "Foo"', 4) + + lines =<< trim END + vim9script + enum Fruit + Apple, + Orange + endenum + var f: Fruit = Fruit.new() + END + v9.CheckSourceFailure(lines, 'E1325: Method "new" not found in class "Fruit"', 6) + + lines =<< trim END + vim9script + enum Fruit + Apple, + Orange + def newFruit() + enddef + endenum + var f: Fruit = Fruit.newFruit() + END + v9.CheckSourceFailure(lines, 'E1325: Method "newFruit" not found in class "Fruit"', 8) + + lines =<< trim END + vim9script + enum Fruit + Apple, + Orange + endenum + def Fn() + var f: Fruit = Fruit.new() + enddef + Fn() + END + v9.CheckSourceFailure(lines, 'E1325: Method "new" not found in class "Fruit"', 1) + + # error in the enum constructor + lines =<< trim END + vim9script + enum Planet + earth + def new() + x = 123 + enddef + endenum + END + v9.CheckSourceFailureList(lines, ['E1100:', 'E1100:'], 1) +enddef + +" Test for checking "this" in an enum constructor +def Test_enum_this_in_constructor() + var lines =<< trim END + vim9script + enum A + Red("A.Red"), + Blue("A.Blue"), + Green("A.Green") + + def new(s: string) + assert_equal(s, string(this)) + enddef + endenum + defcompile + END + v9.CheckSourceSuccess(lines) +enddef + +" Test for using member variables in an enum object +def Test_enum_object_variable() + var lines =<< trim END + vim9script + enum Planet + Jupiter(95), + Saturn(146) + + var moons: number + endenum + assert_equal(95, Planet.Jupiter.moons) + assert_equal(146, Planet.Saturn.moons) + END + v9.CheckSourceSuccess(lines) + + # Use a final object variable + lines =<< trim END + vim9script + enum Planet + Jupiter(95), + Saturn(146) + + final moons: number + def new(n: number) + this.moons = n + enddef + endenum + assert_equal(95, Planet.Jupiter.moons) + assert_equal(146, Planet.Saturn.moons) + END + v9.CheckSourceSuccess(lines) + + # Use a const object variable + lines =<< trim END + vim9script + enum Planet + Mars(false), + Jupiter(true) + + const has_ring: bool + def new(r: bool) + this.has_ring = r + enddef + endenum + assert_equal(false, Planet.Mars.has_ring) + assert_equal(true, Planet.Jupiter.has_ring) + END + v9.CheckSourceSuccess(lines) + + # Use a regular object variable + lines =<< trim END + vim9script + enum Fruit + Apple, + Orange + + final farm: string = 'SunValley' + endenum + assert_equal('SunValley', Fruit.Apple.farm) + assert_equal('SunValley', Fruit.Apple.farm) + END + v9.CheckSourceSuccess(lines) + + # Invoke the default constructor with an object variable + lines =<< trim END + vim9script + enum Fruit + Apple('foo'), + Orange('bar') + + final t: string + endenum + assert_equal('foo', Fruit.Apple.t) + assert_equal('bar', Fruit.Orange.t) + END + v9.CheckSourceSuccess(lines) + + # Invoke the default constructor with an argument but without the object + # variable + lines =<< trim END + vim9script + enum Fruit + Apple, + Orange('bar') + endenum + defcompile + END + v9.CheckSourceFailure(lines, 'E118: Too many arguments for function: new', 5) + + # Define a default constructor with an argument, but don't pass it in when + # defining the enum value + lines =<< trim END + vim9script + enum Fruit + Apple(5), + Orange + + def new(t: number) + enddef + endenum + defcompile + END + v9.CheckSourceFailure(lines, 'E119: Not enough arguments for function: new', 8) +enddef + +" Test for using a custom constructor with an enum +def Test_enum_custom_constructor() + # space before "(" + var lines =<< trim END + vim9script + enum Fruit + Apple(10), + Orange (20) + + def new(t: number) + enddef + endenum + defcompile + END + v9.CheckSourceFailure(lines, "E1068: No white space allowed before '(': Orange (20)", 4) + + # no closing ")" + lines =<< trim END + vim9script + enum Fruit + Apple(10), + Orange (20 + + def new(t: number) + enddef + endenum + defcompile + END + v9.CheckSourceFailure(lines, "E1068: No white space allowed before '(': Orange (20", 4) + + # Specify constructor arguments split across multiple lines + lines =<< trim END + vim9script + enum Fruit + Apple(10, + 'foo'), Orange(20, + 'bar'), + Pear(30, + 'baz'), Mango(40, + 'qux') + + final n: number + final s: string + def new(t: number, str: string) + this.n = t + this.s = str + enddef + endenum + defcompile + assert_equal([10, 'foo'], [Fruit.Apple.n, Fruit.Apple.s]) + assert_equal([20, 'bar'], [Fruit.Orange.n, Fruit.Orange.s]) + assert_equal([30, 'baz'], [Fruit.Pear.n, Fruit.Pear.s]) + assert_equal([40, 'qux'], [Fruit.Mango.n, Fruit.Mango.s]) + END + v9.CheckSourceSuccess(lines) + + # specify multiple enums with constructor arguments in a single line + lines =<< trim END + vim9script + enum Fruit + Apple(10, 'foo'), Orange(20, 'bar'), Pear(30, 'baz'), Mango(40, 'qux') + const n: number + const s: string + endenum + defcompile + assert_equal([10, 'foo'], [Fruit.Apple.n, Fruit.Apple.s]) + assert_equal([20, 'bar'], [Fruit.Orange.n, Fruit.Orange.s]) + assert_equal([30, 'baz'], [Fruit.Pear.n, Fruit.Pear.s]) + assert_equal([40, 'qux'], [Fruit.Mango.n, Fruit.Mango.s]) + END + v9.CheckSourceSuccess(lines) +enddef + +" Test for using class variables in an enum class +def Test_enum_class_variable() + var lines =<< trim END + vim9script + enum Fruit + Apple, + Orange + + static var farm: string = 'SunValley' + endenum + assert_equal('SunValley', Fruit.farm) + END + v9.CheckSourceSuccess(lines) +enddef + +" Test for converting an enum value to a string and then back to an enum value +def Test_enum_eval() + var lines =<< trim END + vim9script + enum Color + Red, + Blue + endenum + var s: string = string(Color.Blue) + var e = eval(s) + assert_equal(Color.Blue, e) + assert_equal(1, e.ordinal) + END + v9.CheckSourceSuccess(lines) +enddef + +" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker -- cgit v1.2.3