/*
 * Copyright 2011 The Closure Compiler Authors.
 *
 * 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.google.javascript.jscomp;

/**
 * Unit tests for {@link TransformAMDToCJSModule}
 */
public final class TransformAMDToCJSModuleTest extends CompilerTestCase {

  @Override protected CompilerPass getProcessor(Compiler compiler) {
    return new TransformAMDToCJSModule(compiler);
  }

  @Override
  protected int getNumRepetitions() {
    return 1;
  }

  public void testDefine() {
    test("define(['foo', 'bar'], function(foo, bar) { foo(bar); bar+1; })",
        "var foo=require('foo'); var bar=require('bar');foo(bar);bar+1");
    test("define(['foo', 'bar'], function(foo, bar, baz) { foo(bar); bar+1; })",
        "var foo=require('foo'); var bar=require('bar');" +
        "var baz = null;foo(bar);bar+1");
    test("define(['foo', 'bar'], function(foo, bar) { return { test: 1 } })",
        "var foo=require('foo'); var bar=require('bar');" +
        "module.exports={test:1}");
    test("define(['foo', 'bar'], function(foo, bar, exports) { " +
        "return { test: 1 } })",
        "var foo=require('foo'); var bar=require('bar');" +
        "module.exports={test:1}");
    test("define(['foo', 'bar'], function(foo, bar, exports, module) { " +
        "return { test: 1 } })",
        "var foo=require('foo'); var bar=require('bar');" +
        "module.exports={test:1}");
    test("define(['foo', 'bar'], function(foo, bar, exports, module, baz) { " +
        "return { test: 1 } })",
        "var foo=require('foo'); var bar=require('bar');var baz = null;" +
        "module.exports={test:1}");
    test("define(['foo', 'bar'], function(foo) { return { test: 1 } })",
        "var foo=require('foo'); require('bar'); module.exports={test:1}");
    test("define(['foo', 'bar'], function(test) { return { test: 1 } })",
        "var test=require('foo'); require('bar'); module.exports={test:1}");
  }

  public void testVarRenaming() {
    final String suffix = TransformAMDToCJSModule.VAR_RENAME_SUFFIX;
    test("var foo; define(['foo', 'bar'], function(foo, bar) { " +
        "foo(bar); bar+1; })",
        "var foo; var foo" + suffix +"0=require('foo');" +
        "var bar=require('bar');foo" + suffix +"0(bar);bar+1");
    test("function foo() {}; define(['foo', 'bar'], " +
        "function(foo, bar) { foo(bar); bar+1; })",
        "function foo() {}; var foo" + suffix +"0=require('foo'); " +
        "var bar=require('bar');foo" + suffix +"0(bar);bar+1");
  }

  public void testDefineOnlyFunction() {
    test("define(function() { return { test: 1 } })",
        "module.exports={test:1}");
    test("define(function(exports, module) { return { test: 1 } })",
        "module.exports={test:1}");
  }

  public void testObjectLit() {
    test("define({foo: 'bar'})", "module.exports={foo: 'bar'}");
  }

  public void testPlugins() {
    test("define(['foo', 'text!foo'], function(foo, text) {})",
        "var foo = require('foo'); var text = null;",
        null, TransformAMDToCJSModule.REQUIREJS_PLUGINS_NOT_SUPPORTED_WARNING);
    test("define(['foo', 'text!foo?bar'], function(foo, bar) {})",
        "var foo = require('foo'); var bar = require('bar'); ",
        null, TransformAMDToCJSModule.REQUIREJS_PLUGINS_NOT_SUPPORTED_WARNING);
    test("define(['foo', 'text!foo?:bar'], function(foo, bar) {})",
        "var foo = require('foo'); var bar = null;",
        null, TransformAMDToCJSModule.REQUIREJS_PLUGINS_NOT_SUPPORTED_WARNING);
  }

  public void testUnsupportedForms() {
    testUnsupported("define()");
    testUnsupported("define([], function() {}, 1)");
    testUnsupported("define({}, function() {})");
    testUnsupported("define('test', function() {})");
    testUnsupported("define([])");
    testUnsupported("define(true)");
    testUnsupported("define(1)");
    testNonTopLevelDefine("var x = define(function() {});");
    testNonTopLevelDefine("if(define(function() {})) {}");
  }

  public void testLocalDefine() {
    testSame("(function() { function define() {}; define({}); })()");
  }

  private void testUnsupported(String js) {
    testError(js, TransformAMDToCJSModule.UNSUPPORTED_DEFINE_SIGNATURE_ERROR);
  }

  private void testNonTopLevelDefine(String js) {
    testError(js, TransformAMDToCJSModule.NON_TOP_LEVEL_STATEMENT_DEFINE_ERROR);
  }

}
