/*
PERMUTE_ARGS:
RUN_OUTPUT:
---
Success
---
*/

extern(C) int printf(const char*, ...);

/**********************************************/

enum Bar
{
    bar2 = 2,
    bar3,
    bar4 = 0
}

void test1()
{
    Bar b;

    assert(b == 2);
}

/**********************************************/

void test2()
{
    enum E
    {
        a=-1
    }

    assert(E.min == -1);
    assert(E.max == -1);
}


/**********************************************/

void test3()
{
    enum E
    {
        a = 1,
        b = -1,
        c = 3,
        d = 2
    }

    assert(E.min == -1);
    assert(E.max == 3);
}

/**********************************************/

void test4()
{
    enum E
    {
        a = -1,
        b = -1,
        c = -3,
        d = -3
    }

    assert(E.min==-3);
    assert(E.max==-1);
}

/**********************************************/

enum Enum5
{
    A = 3,
    B = 10,
    E = -5,
}

void test5()
{
    assert(Enum5.init == Enum5.A);
    assert(Enum5.init == 3);
    Enum5 e;
    assert(e == Enum5.A);
    assert(e == 3);
}

/***********************************/

enum E6 : byte
{
    NORMAL_VALUE = 0,
    REFERRING_VALUE = NORMAL_VALUE + 1,
    OTHER_NORMAL_VALUE = 2
}

void foo6(E6 e)
{
}

void test6()
{
     foo6(E6.NORMAL_VALUE);
     foo6(E6.REFERRING_VALUE);
     foo6(E6.OTHER_NORMAL_VALUE);
}

/**********************************************/
// https://issues.dlang.org/show_bug.cgi?id=2407

int i2407;

void add2407() { ++i2407; }
void sub2407() { --i2407; }

enum EF2407f : void function()
{
    a = &add2407,
    s = &sub2407,
}

enum EF2407s
{
    a = &add2407,
    s = &sub2407,
}

enum
{
    a2407 = &add2407,
    s2407 = &sub2407,
}

enum : void function()
{
    at2407 = &add2407,
    st2407 = &sub2407,
}

enum EEF2407 : EF2407s
{
    a = EF2407s.a,
    s = EF2407s.s,
}

void test2407()
{
    alias i2407 i;

    EF2407f.a();
    assert(i == 1);
    EF2407f.s();
    assert(i == 0);

    EF2407s.a();
    assert(i == 1);
    EF2407s.s();
    assert(i == 0);

    a2407();
    assert(i == 1);
    s2407();
    assert(i == 0);

    at2407();
    assert(i == 1);
    st2407();
    assert(i == 0);

    EEF2407.a();
    assert(i == 1);
    EEF2407.s();
    assert(i == 0);

    EEF2407.init();
    assert(i == 1);

    struct S { int i; }
    enum ES : S
    {
        a = S(1),
        b = S(3),
        c = S(2),
    }
    static assert(ES.init == S(1));
    static assert(!__traits(compiles, ES.min));
    static assert(!__traits(compiles, ES.max));

    enum EES : ES
    {
        a = ES.a,
        b = ES.b,
        c = ES.c,
    }
    static assert(EES.init == S(1));
    static assert(!__traits(compiles, EES.min));
    static assert(!__traits(compiles, EES.max));

    ES es = ES.c;
    assert(es.i == 2);
    es = ES.b;
    assert(es.i == 3);

    class C { this(int i) { this.i = i; } int i; }
    enum EC : C
    {
        a = new C(42),
        b = null,
        c = new C(1),
        d = new C(33),
    }
    static assert(EC.init.i == (new C(42)).i);
    static assert(!__traits(compiles, EC.min));
    static assert(!__traits(compiles, EC.max));

    EC ec = EC.d;
    assert(ec.i == 33);
    ec = EC.b;
    assert(ec is null);
}

/**********************************************/
// https://issues.dlang.org/show_bug.cgi?id=3096

void test3096()
{
    template Tuple(T...) { alias Tuple = T; }

    template Base(E)
    {
        static if(is(E B == enum))
            alias Base = B;
    }

    template GetEnum(T)
    {
        enum GetEnum { v = T.init }
    }

    struct S { }
    class C { }

    foreach (Type; Tuple!(char, wchar, dchar, byte, ubyte,
                          short, ushort, int, uint, long,
                          ulong, float, double, real, S, C))
    {
        static assert(is(Base!(GetEnum!Type) == Type));
    }
}

/**********************************************/
// https://issues.dlang.org/show_bug.cgi?id=7719

enum foo7719 = bar7719;
enum { bar7719 = 1 }

/**********************************************/
// https://issues.dlang.org/show_bug.cgi?id=9845

enum { A9845 = B9845 }
enum { B9845 = 1 }

/**********************************************/
// https://issues.dlang.org/show_bug.cgi?id=9846

const int A9846 = B9846;
enum { B9846 = 1 }

/**********************************************/
// https://issues.dlang.org/show_bug.cgi?id=10105

enum E10105 : char[1] { a = "a" }

/**********************************************/
// https://issues.dlang.org/show_bug.cgi?id=10113

enum E10113 : string
{
    a = "a",
    b = "b",
    abc = "abc"
}

void test10113()
{
    E10113 v = E10113.b;
    bool check = false;

    final switch (v) {
    case E10113.a: assert(false);
    case E10113.b: check = true; break;
    case E10113.abc: assert(false);
    }

    assert(check);
}

/**********************************************/
// https://issues.dlang.org/show_bug.cgi?id=10503

@property int octal10503(string num)()
{
    return num.length;
}

enum
{
    A10503 = octal10503!"2000000",
    B10503 = octal10503!"4000",
}

/**********************************************/
// https://issues.dlang.org/show_bug.cgi?id=10505

enum
{
    a10505 = true,
    b10505 = 10.0f,
    c10505 = false,
    d10505 = 10,
    e10505 = null
}

static assert(is(typeof(a10505) == bool));
static assert(is(typeof(b10505) == float));
static assert(is(typeof(c10505) == bool));
static assert(is(typeof(d10505) == int));
static assert(is(typeof(e10505) == typeof(null)));

/**********************************************/
// https://issues.dlang.org/show_bug.cgi?id=10561

void test10561()
{
    template Tuple(T...) { alias Tuple = T; }

    foreach (Type; Tuple!(char, wchar, dchar, byte, ubyte,
                          short, ushort, int, uint, long,
                          ulong, float, double, real))
    {
        enum : Type { v = 0, w = 0, x, y = x }
        static assert(is(typeof(v) == Type));
        static assert(is(typeof(w) == Type));
        static assert(is(typeof(x) == Type));
        static assert(is(typeof(y) == Type));
    }

    class B { }
    class D : B { }
    enum : B { a = new D, b = new B, c = null }
    static assert(is(typeof(a) == B));
    static assert(is(typeof(b) == B));
    static assert(is(typeof(c) == B));

    struct S { this(int) { } }
    enum : S { d = S(1), e = S(2) }
    static assert(is(typeof(d) == S));
    static assert(is(typeof(e) == S));

    enum : float[] { f = [], g = [1.0, 2.0], h = [1.0f] }
    static assert(is(typeof(f) == float[]));
    static assert(is(typeof(g) == float[]));
    static assert(is(typeof(h) == float[]));
}

/**********************************************/
// https://issues.dlang.org/show_bug.cgi?id=10612

int[E10612] ie10612;
E10612[int] ei10612;
E10612[E10612] ee10612;

enum E10612 { a }

/**********************************************/
// https://issues.dlang.org/show_bug.cgi?id=10788

enum v10788 = e10788;
enum : int { e10788 }

/**********************************************/

class C7
{
    enum Policy
    {
        PREFER_READERS,
        PREFER_WRITERS
    }

    void foo1( Policy policy = Policy.PREFER_READERS ) { }
    void foo2( Policy policy = Policy.PREFER_WRITERS ) { }
}

/**********************************************/

void test8()
{
    enum E
    {
        A = B,
        E = D + 7,
        B = 3,
        C,
        D,
    }

    assert(E.A == 3);
    assert(E.B == 3);
    assert(E.C == 4);
    assert(E.D == 5);
    assert(E.E == 12);
    assert(E.max == 12);
}

/**********************************************/
// https://issues.dlang.org/show_bug.cgi?id=13220

enum E13220a;
@(1) enum E13220b;

void test13220()
{
    auto prot = __traits(getProtection, E13220a);
    assert(prot == "public");

    auto udas = __traits(getAttributes, E13220b);
    assert(udas[0] == 1);
}

/**********************************************/

int main()
{
    test1();
    test2();
    test3();
    test4();
    test5();
    test6();
    test2407();
    test10113();
    test10561();
    test8();
    test13220();

    printf("Success\n");
    return 0;
}
