# frozen_string_literal: true

#
# Copyright (C) 2014 - present Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.

require "spec_helper"
require "i18n_extraction/i18nliner_extensions"

describe I18nliner::Extractors::RubyExtractor do
  def extract(source, scope = I18nliner::Scope.new("asdf"))
    sexps = RubyParser.new.parse(source)
    extractor = I18nliner::Extractors::RubyExtractor.new(sexps, scope)
    translations = []
    extractor.each_translation { |translation| translations << translation }
    translations.to_h
  end

  context "labels" do
    it "interprets symbol names as the key" do
      expect(extract("label :thing, :the_foo, :foo, :en => 'Foo'")).to eq({ "asdf.labels.foo" => "Foo" })
      expect(extract("f.label :the_foo, :foo, :en => 'Foo'")).to eq({ "asdf.labels.foo" => "Foo" })
      expect(extract("label_tag :the_foo, :foo, :en => 'Foo'")).to eq({ "asdf.labels.foo" => "Foo" })
    end

    it "infers the key from the method if not provided" do
      expect(extract("label :thing, :the_foo, :en => 'Foo'")).to eq({ "asdf.labels.the_foo" => "Foo" })
      expect(extract("f.label :the_foo, :en => 'Foo'")).to eq({ "asdf.labels.the_foo" => "Foo" })
      expect(extract("label_tag :the_foo, :en => 'Foo'")).to eq({ "asdf.labels.the_foo" => "Foo" })
    end

    it "skips label calls with non-symbol keys (i.e. just a standard label)" do
      expect(extract("label :thing, :the_foo, 'foo'")).to eq({})
      expect(extract("f.label :the_foo, 'foo'")).to eq({})
      expect(extract("label_tag :thing, 'foo'")).to eq({})
    end

    it "does not auto-scope absolute keys" do
      expect(extract("label :thing, :the_foo, :'#foo', :en => 'Foo'")).to eq({ "foo" => "Foo" })
      expect(extract("f.label :the_foo, :'#foo', :en => 'Foo'")).to eq({ "foo" => "Foo" })
      expect(extract("label_tag :the_foo, :'#foo', :en => 'Foo'")).to eq({ "foo" => "Foo" })
    end
  end

  context "nesting" do
    it "ignores i18n calls within i18n method definitions" do
      expect(extract("def t(*args); other.t *args; end")).to eq({})
    end
  end

  context "scoping" do
    it "auto-scopes relative keys to the current scope" do
      expect(extract("t 'foo', 'Foo'")).to eq({ "asdf.foo" => "Foo" })
    end

    it "does not auto-scope absolute keys" do
      expect(extract("t '#foo', 'Foo'")).to eq({ "foo" => "Foo" })
    end

    it "does not auto-scope keys with I18n as the receiver" do
      expect(extract("I18n.t 'foo', 'Foo'")).to eq({ "foo" => "Foo" })
    end

    it "does not auto-scope keys when scope cannot be inferred correctly (e.g. in abstract models)" do
      expect(extract("t 'foo', 'Foo'", I18nliner::Scope.new(""))).to eq({ "foo" => "Foo" })
    end

    it "auto-scopes plugin registration" do
      expect(extract("Canvas::Plugin.register('dim_dim', :web_conferencing, {:name => lambda{ t :name, \"DimDim\" }})")).to eq(
        { "plugins.dim_dim.name" => "DimDim" }
      )
    end

    it "requires explicit keys if a key is provided and there is no scope" do
      expect { extract("t 'foo', 'Foo'", I18nliner::Scope.root) }.to raise_error(/ambiguous translation key/)
    end

    it "does not require explicit keys if the key is inferred and there is no scope" do
      expect(extract("t 'Foo'", I18nliner::Scope.root)).to eq({ "foo_f44ad75d" => "Foo" })
    end

    it "does not scope inferred keys" do
      expect(extract("t 'Hello World'")).to eq({ "hello_world_e2033670" => "Hello World" })
    end
  end

  context "sanitization" do
    it "rejects stuff that looks sufficiently html-y" do
      expect { extract "t 'dude', 'this is <em>important</em>'" }.to raise_error(/html tags in default translation/)
    end

    it "is generally ok with angle brackets" do
      expect(extract("t 'obvious', 'TIL 1 < 2'")).to eq({ "asdf.obvious" => "TIL 1 < 2" })
      expect(extract("t 'email', 'please enter an email, e.g. Joe User <joe@example.com>'")).to eq({ "asdf.email" => "please enter an email, e.g. Joe User <joe@example.com>" })
    end
  end
end
