/**
 * Copyright (c) 2014 SQUARESPACE, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.squarespace.less;

import static com.squarespace.less.ExecuteErrorType.VAR_UNDEFINED;
import static com.squarespace.less.SyntaxErrorType.INCOMPLETE_PARSE;
import static com.squarespace.less.parse.Parselets.QUOTED;
import static com.squarespace.less.parse.Parselets.VARIABLE;
import static com.squarespace.less.parse.Parselets.VARIABLE_CURLY;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotEquals;

import org.testng.annotations.Test;

import com.squarespace.less.core.LessHarness;
import com.squarespace.less.core.LessTestBase;
import com.squarespace.less.model.GenericBlock;
import com.squarespace.less.model.Unit;


public class VariableTest extends LessTestBase {

  @Test
  public void testEquals() {
    assertEquals(var("@a"), var("@a"));

    assertNotEquals(var("@a"), null);
    assertNotEquals(var("@a"), anon("@a"));
    assertNotEquals(var("@a"), var("@b"));
  }

  @Test
  public void testModelReprSafety() {
    var("@a").toString();
  }

  @Test
  public void testParse() throws LessException {
    LessHarness h = new LessHarness(VARIABLE);
    h.parseFails("@", INCOMPLETE_PARSE);
    h.parseFails("@-", INCOMPLETE_PARSE);
    h.parseEquals("@1", var("@1"));
    h.parseEquals("@a", var("@a"));
    h.parseEquals("@@a", var("@@a"));

    h = new LessHarness(VARIABLE_CURLY);
    h.parseFails("@{", INCOMPLETE_PARSE);
    h.parseFails("@{a", INCOMPLETE_PARSE);
    h.parseFails("@{aa", INCOMPLETE_PARSE);
    h.parseEquals("@{aa}", var("@aa", true));
  }

  @Test
  public void testUndefined() throws LessException {
    LessHarness h = new LessHarness();
    h.executeFails(".foo { color: @c; }", VAR_UNDEFINED);
  }

  @Test
  public void testSelfReference() throws LessException {
    GenericBlock defs = defs(
        def("@value", var("@link1")),
        def("@link1", var("@link2")),
        def("@link2", var("@value"))
        );
    LessHarness h = new LessHarness(VARIABLE, defs);
    h.evalFails("@value", VAR_UNDEFINED);
    h.evalFails("@link1", VAR_UNDEFINED);
    h.evalFails("@link2", VAR_UNDEFINED);
  }

  @Test
  public void testSkipCircular() throws LessException {
    GenericBlock frameOne = defs(
        def("@color", color("red"))
        );
    GenericBlock frameTwo = defs(
        def("@color", var("@color"))
        );
    LessHarness h = new LessHarness(VARIABLE, frameOne, frameTwo);
    h.renderEquals("@color", "red");
  }

  @Test
  public void testIndirectReference() throws LessException {
    GenericBlock defs = defs(
        def("@value", dim(12, Unit.PX)),
        def("@real", quoted('"', false, var("@value"))),
        def("@one", kwd("real")),
        def("@two", quoted('"', true, "real"))
        );
    LessHarness h = new LessHarness(VARIABLE, defs);
    h.renderEquals("@@one", "\"12px\"");
    h.renderEquals("@@two", "\"12px\"");
  }

  @Test
  public void testDereference() throws LessException {
    GenericBlock defs = defs(
        def("@var", var("@link1")),
        def("@link1", var("@white")),
        def("@white", color("#fff")),
        def("@color", color("#123")),
        def("@num", dim(1, Unit.PX))
        );
    LessHarness h = new LessHarness(VARIABLE, defs);
    h.renderEquals("@var", "#fff");
    h.renderEquals("@color", "#123");
    h.renderEquals("@num", "1px");
  }

  @Test
  public void testEmbeddedReferences() throws LessException {
    GenericBlock defs = defs(
        def("@a", dim(1, Unit.EM)),
        def("@b", quoted('"', false, anon("foo"))),
        def("@c", dim(2, Unit.PX)),
        def("@d", quoted('"', false, anon("\"bar\""))),
        def("@e", color("#123456"))
        );
    LessHarness h = new LessHarness(QUOTED, defs);
    h.renderEquals("'@{a} @{b} @{c} @{d} @{e}", "'1em foo 2px \"bar\" #123456'");
  }

  @Test
  public void testNestedVariables() throws LessException {
    LessOptions opts = new LessOptions(true);
    LessHarness h = new LessHarness();

    String str = "@a: 1px; .x { @b: #111; .y { .z { key: @a @b; } } }";
    assertEquals(h.execute(str, opts), ".x .y .z{key:1px #111}");

    str = "@a: 1; .x { @a: 2; .y { @a: 3; .z { key: @a; } } }";
    assertEquals(h.execute(str, opts), ".x .y .z{key:3}");
  }

}

@@ -2287,419 +2287,73 @@
  %7D%0A%0A
-  @Test%0A  public void testSelfReference() throws LessException %7B%0A    GenericBlock defs = defs(%0A        def(%22@value%22, var(%22@link1%22)),%0A        def(%22@link1%22, var(%22@link2%22)),%0A        def(%22@link2%22, var(%22@value%22))%0A        );%0A    LessHarness h = new LessHarness(VARIABLE, defs);%0A    h.evalFails(%22@value%22, VAR_UNDEFINED);%0A    h.evalFails(%22@link1%22, VAR_UNDEFINED);%0A    h.evalFails(%22@link2%22, VAR_UNDEFINED);%0A  %7D%0A%0A
+// DISABLED: may restore in future as a pragma feature%0A//
   @Test%0A
   pu
@@ -2340,32 +2340,34 @@
 ature%0A//  @Test%0A
+//
   public void te
@@ -2398,32 +2398,34 @@
 LessException %7B%0A
+//
     GenericBlock
@@ -2434,32 +2434,34 @@
 rameOne = defs(%0A
+//
         def(%22@co
@@ -2476,24 +2476,26 @@
 lor(%22red%22))%0A
+//
         );%0A 
@@ -2489,24 +2489,26 @@
 /        );%0A
+//
     GenericB
@@ -2521,32 +2521,34 @@
 rameTwo = defs(%0A
+//
         def(%22@co
@@ -2564,24 +2564,26 @@
 (%22@color%22))%0A
+//
         );%0A 
@@ -2573,32 +2573,34 @@
 ))%0A//        );%0A
+//
     LessHarness 
@@ -2650,16 +2650,18 @@
 meTwo);%0A
+//
     h.re
@@ -2685,24 +2685,26 @@
 r%22, %22red%22);%0A
+//
   %7D%0A%0A  @Test

Delete self-reference test; disable skip-circular test.