view src/testdir/test_vim9_enum.vim @ 34686:83875247fbc0 v9.1.0224

patch 9.1.0224: cursor may move too many lines over "right" & "below" virt text Commit: https://github.com/vim/vim/commit/515f734e687f28f7199b2a8042197624d9f3ec15 Author: Dylan Thacker-Smith <dylan.ah.smith@gmail.com> Date: Thu Mar 28 12:01:14 2024 +0100 patch 9.1.0224: cursor may move too many lines over "right" & "below" virt text Problem: If a line has "right" & "below" virtual text properties, where the "below" property may be stored first due to lack of ordering between them, then the line height is calculated to be 1 more and causes the cursor to far over the line. Solution: Remove some unnecessary setting of a `next_right_goes_below = TRUE` flag for "below" and "above" text properties. (Dylan Thacker-Smith) I modified a regression test I recently added to cover this case, leveraging the fact that "after", "right" & "below" text properties are being stored in the reverse of the order they are added in. The previous version of this regression test was crafted to workaround this issue so it can be addressed by this separate patch. closes: #14317 Signed-off-by: Dylan Thacker-Smith <dylan.ah.smith@gmail.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
author Christian Brabandt <cb@256bit.org>
date Thu, 28 Mar 2024 12:15:03 +0100
parents 5b25ec43f208
children ad86d59d7510
line wrap: on
line source

" 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<number> = [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<Foo>', typename(Foo.apple))
    assert_equal('enum<Foo>', 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<Foo> but got dict<any>', 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<Foo>', 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<Foo> but got number', 1)

  # Use a List of enums
  lines =<< trim END
    vim9script
    enum Planet
      Mercury,
      Venus,
      Earth
    endenum
    var l1: list<Planet> = [Planet.Mercury, Planet.Venus]
    assert_equal(Planet.Venus, l1[1])
    def Fn()
      var l2: list<Planet> = [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<Fruit>', typename(Fruit))
    assert_equal('enum<Fruit>', 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<Fruit>', typename(a))
    assert_equal('enum<Fruit>', 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<Foo> 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<Foo> 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<Foo> 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> = 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<A>
	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> = 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> = 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