code: package morfologik.stemming;
  
  import static org.assertj.core.api.Assertions.*;
  import static org.junit.Assert.*;
  
  import java.io.IOException;
  import java.net.URL;
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.HashSet;
  import java.util.LinkedHashMap;
  
  import morfologik.fsa.FSA;
  
  import org.assertj.core.api.Assertions;
  import org.junit.Assert;
  import org.junit.Test;
  
  public class DictionaryLookupTest {
    @Test
    public void testApplyReplacements() {
      LinkedHashMap<String, String> conversion = new LinkedHashMap<>();
      conversion.put("'", "`");
      conversion.put("fi", "ﬁ");
      conversion.put("\\a", "ą");
      conversion.put("Barack", "George");
      conversion.put("_", "xx");
      assertEquals("ﬁlut", DictionaryLookup.applyReplacements("filut", conversion));
      assertEquals("ﬁzdrygałką", DictionaryLookup.applyReplacements("fizdrygałk\\a", conversion));
      assertEquals("George Bush", DictionaryLookup.applyReplacements("Barack Bush", conversion));
      assertEquals("xxxxxxxx", DictionaryLookup.applyReplacements("____", conversion));
    }
  
    @Test
    public void testRemovedEncoderProperties() throws IOException {
      final URL url = this.getClass().getResource("test-removed-props.dict");
      try {
        new DictionaryLookup(Dictionary.read(url));
        Assert.fail();
      } catch (IOException e) {
        assertThat(e).hasMessageContaining(
            DictionaryAttribute.ENCODER.propertyName);
      }
    }
  
    @Test
    public void testPrefixDictionaries() throws IOException {
      final URL url = this.getClass().getResource("test-prefix.dict");
      final IStemmer s = new DictionaryLookup(Dictionary.read(url));
  
      assertArrayEquals(new String[] { "Rzeczpospolita", "subst:irreg" },
          stem(s, "Rzeczypospolitej"));
      assertArrayEquals(new String[] { "Rzeczpospolita", "subst:irreg" },
          stem(s, "Rzecząpospolitą"));
  
      // This word is not in the dictionary.
      assertNoStemFor(s, "martygalski");
    }
  
    @Test
    public void testInputConversion() throws IOException {
      final URL url = this.getClass().getResource("test-prefix.dict");
      final IStemmer s = new DictionaryLookup(Dictionary.read(url));
  
      assertArrayEquals(new String[] { "Rzeczpospolita", "subst:irreg" },
          stem(s, "Rzecz\\apospolit\\a"));
  
      assertArrayEquals(new String[] { "Rzeczpospolita", "subst:irreg" },
          stem(s, "krowa\\apospolit\\a"));
    }
  
    /* */
    @Test
    public void testInfixDictionaries() throws IOException {
      final URL url = this.getClass().getResource("test-infix.dict");
      final IStemmer s = new DictionaryLookup(Dictionary.read(url));
  
      Assertions.assertThat(stem(s, "Rzeczypospolitej"))
        .containsExactly("Rzeczpospolita", "subst:irreg");
  
      Assertions.assertThat(stem(s, "Rzeczyccy"))
        .containsExactly("Rzeczycki", "adj:pl:nom:m");
  
      Assertions.assertThat(stem(s, "Rzecząpospolitą"))
        .containsExactly("Rzeczpospolita", "subst:irreg");
  
      // This word is not in the dictionary.
      assertNoStemFor(s, "martygalski");
      
      // This word uses characters that are outside of the encoding range of the dictionary. 
      assertNoStemFor(s, "Rzeczyckiõh");
    }
  
    /* */
    @Test
    public void testWordDataIterator() throws IOException {
      final URL url = this.getClass().getResource("test-infix.dict");
      final DictionaryLookup s = new DictionaryLookup(Dictionary.read(url));
  
      final HashSet<String> entries = new HashSet<String>();
      for (WordData wd : s) {
        entries.add(wd.getWord() + " " + wd.getStem() + " " + wd.getTag());
      }
  
      // Make sure a sample of the entries is present.
      Assertions.assertThat(entries)
        .contains(
            "Rzekunia Rzekuń subst:sg:gen:m",
            "Rzeczkowskie Rzeczkowski adj:sg:nom.acc.voc:n+adj:pl:acc.nom.voc:f.n",
            "Rzecząpospolitą Rzeczpospolita subst:irreg",
            "Rzeczypospolita Rzeczpospolita subst:irreg",
            "Rzeczypospolitych Rzeczpospolita subst:irreg",
            "Rzeczyckiej Rzeczycki adj:sg:gen.dat.loc:f");
    }
  
    /* */
    @Test
    public void testWordDataCloning() throws IOException {
      final URL url = this.getClass().getResource("test-infix.dict");
      final DictionaryLookup s = new DictionaryLookup(Dictionary.read(url));
  
      ArrayList<WordData> words = new ArrayList<WordData>();
      for (WordData wd : s) {
        WordData clone = wd.clone();
        words.add(clone);
      }
  
      // Reiterate and verify that we have the same entries.
      final DictionaryLookup s2 = new DictionaryLookup(Dictionary.read(url));
      int i = 0;
      for (WordData wd : s2) {
        WordData clone = words.get(i++);
        assertEqualSequences(clone.getStem(), wd.getStem());
        assertEqualSequences(clone.getTag(), wd.getTag());
        assertEqualSequences(clone.getWord(), wd.getWord());
      }
  
      // Check collections contract.
      final HashSet<WordData> entries = new HashSet<WordData>();
      try {
        entries.add(words.get(0));
        fail();
      } catch (RuntimeException e) {
        // Expected.
      }
    }
  
    private void assertEqualSequences(CharSequence s1, CharSequence s2) {
      assertEquals(s1.toString(), s2.toString());
    }
  
    /* */
    @Test
    public void testMultibyteEncodingUTF8() throws IOException {
      final URL url = this.getClass().getResource("test-diacritics-utf8.dict");
      Dictionary read = Dictionary.read(url);
      final IStemmer s = new DictionaryLookup(read);
  
      assertArrayEquals(new String[] { "merge", "001" }, stem(s, "mergeam"));
      assertArrayEquals(new String[] { "merge", "002" }, stem(s, "merseserăm"));
    }
  
    /* */
    @Test
    public void testSynthesis() throws IOException {
      final URL url = this.getClass().getResource("test-synth.dict");
      final IStemmer s = new DictionaryLookup(Dictionary.read(url));
  
      assertArrayEquals(new String[] { "miała", null }, stem(s,
          "mieć|verb:praet:sg:ter:f:?perf"));
      assertArrayEquals(new String[] { "a", null }, stem(s, "a|conj"));
      assertArrayEquals(new String[] {}, stem(s, "dziecko|subst:sg:dat:n"));
  
      // This word is not in the dictionary.
      assertNoStemFor(s, "martygalski");
    }
  
    /* */
    @Test
    public void testInputWithSeparators() throws IOException {
      final URL url = this.getClass().getResource("test-separators.dict");
      final DictionaryLookup s = new DictionaryLookup(Dictionary.read(url));
  
      /*
       * Attemp to reconstruct input sequences using WordData iterator.
       */
      ArrayList<String> sequences = new ArrayList<String>();
      for (WordData wd : s) {
        sequences.add("" + wd.getWord() + " " + wd.getStem() + " "
            + wd.getTag());
      }
      Collections.sort(sequences);
  
      assertEquals("token1 null null", sequences.get(0));
      assertEquals("token2 null null", sequences.get(1));
      assertEquals("token3 null +", sequences.get(2));
      assertEquals("token4 token2 null", sequences.get(3));
      assertEquals("token5 token2 null", sequences.get(4));
      assertEquals("token6 token2 +", sequences.get(5));
      assertEquals("token7 token2 token3+", sequences.get(6));
      assertEquals("token8 token2 token3++", sequences.get(7));
    }
  
    /* */
    @Test
    public void testSeparatorInLookupTerm() throws IOException {
      FSA fsa = FSA.read(getClass().getResourceAsStream("test-separator-in-lookup.fsa"));
  
      DictionaryMetadata metadata = new DictionaryMetadataBuilder()
        .separator('+')
        .encoding("iso8859-1")
        .encoder(EncoderType.INFIX)
        .build();
  
      final DictionaryLookup s = new DictionaryLookup(new Dictionary(fsa, metadata));
      assertEquals(0, s.lookup("l+A").size());
    }
  
    /* */
    @Test
    public void testGetSeparator() throws IOException {
      final URL url = this.getClass().getResource("test-separators.dict");
      final DictionaryLookup s = new DictionaryLookup(Dictionary.read(url));
      assertEquals('+', s.getSeparatorChar());
    }
  
    /* */
    public static String asString(CharSequence s) {
      if (s == null)
        return null;
      return s.toString();
    }
  
    /* */
    public static String[] stem(IStemmer s, String word) {
      ArrayList<String> result = new ArrayList<String>();
      for (WordData wd : s.lookup(word)) {
        result.add(asString(wd.getStem()));
        result.add(asString(wd.getTag()));
      }
      return result.toArray(new String[result.size()]);
    }
  
    /* */
    public static void assertNoStemFor(IStemmer s, String word) {
      assertArrayEquals(new String[] {}, stem(s, word));
    }
  }
  