/*
 * Copyright 2015 Google 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.google.template.soy.msgs.internal;

import static com.google.common.truth.Truth.assertThat;
import static java.nio.charset.StandardCharsets.UTF_16;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import com.google.template.soy.msgs.restricted.SoyMsgPart;
import com.google.template.soy.msgs.restricted.SoyMsgPlaceholderPart;
import com.google.template.soy.msgs.restricted.SoyMsgPluralCaseSpec;
import com.google.template.soy.msgs.restricted.SoyMsgPluralPart;
import com.google.template.soy.msgs.restricted.SoyMsgRawTextPart;

import junit.framework.TestCase;

import java.util.Random;
import java.util.Set;

/**
 * Unit tests for SoyMsgIdComputer.
 *
 */
public class SoyMsgIdComputerTest extends TestCase {


  private static final Random RANDOM_GEN = new Random();


  private static final ImmutableList<SoyMsgPart> HELLO_WORLD_MSG_PARTS =
      ImmutableList.<SoyMsgPart>of(SoyMsgRawTextPart.of("Hello world!"));

  private static final ImmutableList<SoyMsgPart> HELLO_NAME_MSG_PARTS = ImmutableList.of(
      SoyMsgRawTextPart.of("Hello "), new SoyMsgPlaceholderPart("NAME"),
      SoyMsgRawTextPart.of("!"));

  private static final ImmutableList<SoyMsgPart> PLURAL_MSG_PARTS =
      ImmutableList.<SoyMsgPart>of(
          new SoyMsgPluralPart(
              "NUM_0",
              0,
              ImmutableList.of(
                  SoyMsgPluralPart.Case.create(
                      new SoyMsgPluralCaseSpec(1),
                      ImmutableList.<SoyMsgPart>of(SoyMsgRawTextPart.of("Once"))),
                  SoyMsgPluralPart.Case.create(
                      new SoyMsgPluralCaseSpec(SoyMsgPluralCaseSpec.Type.FEW),
                      ImmutableList.<SoyMsgPart>of(
                          new SoyMsgPlaceholderPart("NUM_1"), SoyMsgRawTextPart.of(" times"))),
                  SoyMsgPluralPart.Case.create(
                      new SoyMsgPluralCaseSpec(SoyMsgPluralCaseSpec.Type.OTHER),
                      ImmutableList.<SoyMsgPart>of(SoyMsgRawTextPart.of("Lots"))))));


  public void testFingerprint() {

    Set<Long> seenFps = Sets.newHashSetWithExpectedSize(100);
    byte[] bytes = new byte[20];
    for (int i = 0; i < 100; i++) {
      RANDOM_GEN.nextBytes(bytes);
      String randomString = new String(bytes, 0, 10 + RANDOM_GEN.nextInt(10), UTF_16);
      long fp = SoyMsgIdComputer.fingerprint(randomString);
      assertThat(seenFps).doesNotContain(fp);
      seenFps.add(fp);
    }
  }


  public void testBuildMsgContentStrForMsgIdComputation() {
    assertThat(SoyMsgIdComputer.buildMsgContentStrForMsgIdComputation(HELLO_WORLD_MSG_PARTS, false))
        .isEqualTo("Hello world!");
    assertThat(SoyMsgIdComputer.buildMsgContentStrForMsgIdComputation(HELLO_WORLD_MSG_PARTS, true))
        .isEqualTo("Hello world!");

    assertThat(SoyMsgIdComputer.buildMsgContentStrForMsgIdComputation(HELLO_NAME_MSG_PARTS, false))
        .isEqualTo("Hello NAME!");
    assertThat(SoyMsgIdComputer.buildMsgContentStrForMsgIdComputation(HELLO_NAME_MSG_PARTS, true))
        .isEqualTo("Hello {NAME}!");

    assertThat(SoyMsgIdComputer.buildMsgContentStrForMsgIdComputation(PLURAL_MSG_PARTS, false))
        .isEqualTo("{NUM_0,plural,=1{Once}few{NUM_1 times}other{Lots}}");
    assertThat(SoyMsgIdComputer.buildMsgContentStrForMsgIdComputation(PLURAL_MSG_PARTS, true))
        .isEqualTo("{NUM_0,plural,=1{Once}few{{NUM_1} times}other{Lots}}");
  }


  public void testKnownMsgIds() {

    // Important: Do not change these hard-coded values. Changes to the algorithm will break
    // backwards compatibility.

    assertThat(SoyMsgIdComputer.computeMsgId(HELLO_WORLD_MSG_PARTS, null, null))
        .isEqualTo(3022994926184248873L);
    assertThat(SoyMsgIdComputer.computeMsgId(HELLO_WORLD_MSG_PARTS, null, "text/html"))
        .isEqualTo(3022994926184248873L);

    assertThat(SoyMsgIdComputer.computeMsgId(HELLO_NAME_MSG_PARTS, null, null))
        .isEqualTo(6936162475751860807L);
    assertThat(SoyMsgIdComputer.computeMsgId(HELLO_NAME_MSG_PARTS, null, "text/html"))
        .isEqualTo(6936162475751860807L);

    assertThat(SoyMsgIdComputer.computeMsgId(PLURAL_MSG_PARTS, null, null))
        .isEqualTo(947930983556630648L);
    assertThat(SoyMsgIdComputer.computeMsgIdUsingBracedPhs(PLURAL_MSG_PARTS, null, null))
        .isEqualTo(1429579464553183506L);

    ImmutableList<SoyMsgPart> archiveMsgParts =
        ImmutableList.<SoyMsgPart>of(SoyMsgRawTextPart.of("Archive"));
    assertThat(SoyMsgIdComputer.computeMsgId(archiveMsgParts, "noun", null))
        .isEqualTo(7224011416745566687L);
    assertThat(SoyMsgIdComputer.computeMsgId(archiveMsgParts, "verb", null))
        .isEqualTo(4826315192146469447L);

    ImmutableList<SoyMsgPart> unicodeMsgParts = ImmutableList.of(
        new SoyMsgPlaceholderPart("\u2222\uEEEE"), SoyMsgRawTextPart.of("\u9EC4\u607A"));
    assertThat(SoyMsgIdComputer.computeMsgId(unicodeMsgParts, null, null))
        .isEqualTo(7971596007260280311L);
    assertThat(SoyMsgIdComputer.computeMsgId(unicodeMsgParts, null, "application/javascript"))
        .isEqualTo(5109146044343713753L);
  }

}
