/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * 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.android.tools.lint.checks;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.android.builder.model.AndroidProject;
import com.android.builder.model.ProductFlavor;
import com.android.builder.model.ProductFlavorContainer;
import com.android.builder.model.Variant;
import com.android.tools.lint.detector.api.Detector;
import com.android.tools.lint.detector.api.Project;

import java.io.File;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

@SuppressWarnings("javadoc")
public class TranslationDetectorTest extends AbstractCheckTest {
    @Override
    protected Detector getDetector() {
        return new TranslationDetector();
    }

    @Override
    protected boolean includeParentPath() {
        return true;
    }

    public void testTranslation() throws Exception {
        TranslationDetector.sCompleteRegions = false;
        assertEquals(
            // Sample files from the Home app
            "res/values/strings.xml:20: Error: \"show_all_apps\" is not translated in \"nl-NL\" (Dutch: Netherlands) [MissingTranslation]\n" +
            "    <string name=\"show_all_apps\">All</string>\n" +
            "            ~~~~~~~~~~~~~~~~~~~~\n" +
            "res/values/strings.xml:23: Error: \"menu_wallpaper\" is not translated in \"nl-NL\" (Dutch: Netherlands) [MissingTranslation]\n" +
            "    <string name=\"menu_wallpaper\">Wallpaper</string>\n" +
            "            ~~~~~~~~~~~~~~~~~~~~~\n" +
            "res/values/strings.xml:25: Error: \"menu_settings\" is not translated in \"cs\" (Czech), \"de-DE\" (German: Germany), \"es\" (Spanish), \"es-US\" (Spanish: United States), \"nl-NL\" (Dutch: Netherlands) [MissingTranslation]\n" +
            "    <string name=\"menu_settings\">Settings</string>\n" +
            "            ~~~~~~~~~~~~~~~~~~~~\n" +
            "res/values-cs/arrays.xml:3: Error: \"security_questions\" is translated here but not found in default locale [ExtraTranslation]\n" +
            "  <string-array name=\"security_questions\">\n" +
            "                ~~~~~~~~~~~~~~~~~~~~~~~~~\n" +
            "    res/values-es/strings.xml:12: Also translated here\n" +
            "res/values-de-rDE/strings.xml:11: Error: \"continue_skip_label\" is translated here but not found in default locale [ExtraTranslation]\n" +
            "    <string name=\"continue_skip_label\">\"Weiter\"</string>\n" +
            "            ~~~~~~~~~~~~~~~~~~~~~~~~~~\n" +
            "5 errors, 0 warnings\n",

            lintProject(
                 "res/values/strings.xml",
                 "res/values-cs/strings.xml",
                 "res/values-de-rDE/strings.xml",
                 "res/values-es/strings.xml",
                 "res/values-es-rUS/strings.xml",
                 "res/values-land/strings.xml",
                 "res/values-cs/arrays.xml",
                 "res/values-es/donottranslate.xml",
                 "res/values-nl-rNL/strings.xml"));
    }

    public void testTranslationWithCompleteRegions() throws Exception {
        TranslationDetector.sCompleteRegions = true;
        assertEquals(
            // Sample files from the Home app
            "res/values/strings.xml:19: Error: \"home_title\" is not translated in \"es-US\" (Spanish: United States) [MissingTranslation]\n" +
            "    <string name=\"home_title\">Home Sample</string>\n" +
            "            ~~~~~~~~~~~~~~~~~\n" +
            "res/values/strings.xml:20: Error: \"show_all_apps\" is not translated in \"es-US\" (Spanish: United States), \"nl-NL\" (Dutch: Netherlands) [MissingTranslation]\n" +
            "    <string name=\"show_all_apps\">All</string>\n" +
            "            ~~~~~~~~~~~~~~~~~~~~\n" +
            "res/values/strings.xml:23: Error: \"menu_wallpaper\" is not translated in \"es-US\" (Spanish: United States), \"nl-NL\" (Dutch: Netherlands) [MissingTranslation]\n" +
            "    <string name=\"menu_wallpaper\">Wallpaper</string>\n" +
            "            ~~~~~~~~~~~~~~~~~~~~~\n" +
            "res/values/strings.xml:25: Error: \"menu_settings\" is not translated in \"cs\" (Czech), \"de-DE\" (German: Germany), \"es-US\" (Spanish: United States), \"nl-NL\" (Dutch: Netherlands) [MissingTranslation]\n" +
            "    <string name=\"menu_settings\">Settings</string>\n" +
            "            ~~~~~~~~~~~~~~~~~~~~\n" +
            "res/values/strings.xml:29: Error: \"wallpaper_instructions\" is not translated in \"es-US\" (Spanish: United States) [MissingTranslation]\n" +
            "    <string name=\"wallpaper_instructions\">Tap picture to set portrait wallpaper</string>\n" +
            "            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" +
            "    res/values-land/strings.xml:19: <No location-specific message\n" +
            "res/values-de-rDE/strings.xml:11: Error: \"continue_skip_label\" is translated here but not found in default locale [ExtraTranslation]\n" +
            "    <string name=\"continue_skip_label\">\"Weiter\"</string>\n" +
            "            ~~~~~~~~~~~~~~~~~~~~~~~~~~\n" +
            "6 errors, 0 warnings\n",

            lintProject(
                 "res/values/strings.xml",
                 "res/values-cs/strings.xml",
                 "res/values-de-rDE/strings.xml",
                 "res/values-es-rUS/strings.xml",
                 "res/values-land/strings.xml",
                 "res/values-nl-rNL/strings.xml"));
    }

    public void testBcp47() throws Exception {
        TranslationDetector.sCompleteRegions = false;
        assertEquals(""
                + "res/values/strings.xml:25: Error: \"menu_settings\" is not translated in \"tlh\" (Klingon; tlhIngan-Hol) [MissingTranslation]\n"
                + "    <string name=\"menu_settings\">Settings</string>\n"
                + "            ~~~~~~~~~~~~~~~~~~~~\n"
                + "1 errors, 0 warnings\n",

                lintProject(
                        "res/values/strings.xml",
                        "res/values-cs/strings.xml=>res/values-b+tlh/strings.xml"));
    }

    public void testHandleBom() throws Exception {
        // This isn't really testing translation detection; it's just making sure that the
        // XML parser doesn't bomb on BOM bytes (byte order marker) at the beginning of
        // the XML document
        assertEquals(
            "No warnings.",
            lintProject(
                 "res/values-de/strings.xml=>res/values/strings.xml"
            ));
    }

    public void testTranslatedArrays() throws Exception {
        TranslationDetector.sCompleteRegions = true;
        assertEquals(
            "No warnings.",

            lintProject(
                 "res/values/translatedarrays.xml",
                 "res/values-cs/translatedarrays.xml"));
    }

    public void testTranslationSuppresss() throws Exception {
        TranslationDetector.sCompleteRegions = false;
        assertEquals(
            "No warnings.",

            lintProject(
                    "res/values/strings_ignore.xml=>res/values/strings.xml",
                    "res/values-es/strings_ignore.xml=>res/values-es/strings.xml",
                    "res/values-nl-rNL/strings.xml=>res/values-nl-rNL/strings.xml"));
    }

    public void testMixedTranslationArrays() throws Exception {
        // See issue http://code.google.com/p/android/issues/detail?id=29263
        assertEquals(
                "No warnings.",

                lintProject(
                        "res/values/strings3.xml=>res/values/strings.xml",
                        "res/values-fr/strings.xml=>res/values-fr/strings.xml"));
    }

    public void testLibraryProjects() throws Exception {
        // If a library project provides additional locales, that should not force
        // the main project to include all those translations
        assertEquals(
            "No warnings.",

             lintProject(
                 // Master project
                 "multiproject/main-manifest.xml=>AndroidManifest.xml",
                 "multiproject/main.properties=>project.properties",
                 "res/values/strings2.xml",

                 // Library project
                 "multiproject/library-manifest.xml=>../LibraryProject/AndroidManifest.xml",
                 "multiproject/library.properties=>../LibraryProject/project.properties",

                 "res/values/strings.xml=>../LibraryProject/res/values/strings.xml",
                 "res/values-cs/strings.xml=>../LibraryProject/res/values-cs/strings.xml",
                 "res/values-cs/strings.xml=>../LibraryProject/res/values-de/strings.xml",
                 "res/values-cs/strings.xml=>../LibraryProject/res/values-nl/strings.xml"
             ));
    }

    public void testNonTranslatable1() throws Exception {
        TranslationDetector.sCompleteRegions = true;
        assertEquals(
            "res/values-nb/nontranslatable.xml:3: Error: The resource string \"dummy\" has been marked as translatable=\"false\" [ExtraTranslation]\n" +
            "    <string name=\"dummy\">Ignore Me</string>\n" +
            "            ~~~~~~~~~~~~\n" +
            "1 errors, 0 warnings\n" +
            "",

            lintProject("res/values/nontranslatable.xml",
                    "res/values/nontranslatable2.xml=>res/values-nb/nontranslatable.xml"));
    }

    public void testNonTranslatable2() throws Exception {
        TranslationDetector.sCompleteRegions = true;
        assertEquals(
            "res/values-nb/nontranslatable.xml:3: Error: Non-translatable resources should only be defined in the base values/ folder [ExtraTranslation]\n" +
            "    <string name=\"dummy\" translatable=\"false\">Ignore Me</string>\n" +
            "                         ~~~~~~~~~~~~~~~~~~~~\n" +
            "1 errors, 0 warnings\n" +
            "",

            lintProject("res/values/nontranslatable.xml=>res/values-nb/nontranslatable.xml"));
    }

    public void testNonTranslatable3() throws Exception {
        // Regression test for https://code.google.com/p/android/issues/detail?id=92861
        // Don't treat "google_maps_key" or "google_maps_key_instructions" as translatable
        TranslationDetector.sCompleteRegions = true;
        assertEquals(
                "No warnings.",

                lintProject("res/values/google_maps_api.xml",
                        "res/values/strings2.xml",
                        "res/values/strings2.xml=>res/values-nb/strings2.xml"));
    }

    public void testSpecifiedLanguageOk() throws Exception {
        TranslationDetector.sCompleteRegions = false;
        assertEquals(
            "No warnings.",

            lintProject(
                 "res/values-es/strings.xml=>res/values/strings.xml",
                 "res/values-es/strings.xml=>res/values-es/strings.xml",
                 "res/values-es-rUS/strings.xml"));
    }

    public void testSpecifiedLanguage() throws Exception {
        TranslationDetector.sCompleteRegions = false;
        assertEquals(
            "No warnings.",

            lintProject(
                 "res/values-es/strings_locale.xml=>res/values/strings.xml",
                 "res/values-es-rUS/strings.xml"));
    }

    public void testAnalytics() throws Exception {
        // See http://code.google.com/p/android/issues/detail?id=43070
        assertEquals(
                "No warnings.",

                lintProject(
                        "res/values/analytics.xml",
                        "res/values-es/donottranslate.xml" // to make app multilingual
                ));
    }

    public void testIssue33845() throws Exception {
        // See http://code.google.com/p/android/issues/detail?id=33845
        assertEquals(""
                + "res/values/strings.xml:5: Error: \"dateTimeFormat\" is not translated in \"de\" (German) [MissingTranslation]\n"
                + "    <string name=\"dateTimeFormat\">MM/dd/yyyy - HH:mm</string>\n"
                + "            ~~~~~~~~~~~~~~~~~~~~~\n"
                + "1 errors, 0 warnings\n",

                lintProject(
                        "locale33845/.classpath=>.classpath",
                        "locale33845/AndroidManifest.xml=>AndroidManifest.xml",
                        "locale33845/project.properties=>project.properties",
                        "locale33845/res/values/strings.xml=>res/values/strings.xml",
                        "locale33845/res/values-de/strings.xml=>res/values-de/strings.xml",
                        "locale33845/res/values-en-rGB/strings.xml=>res/values-en-rGB/strings.xml"
                ));
    }

    public void testIssue33845b() throws Exception {
        // Similar to issue 33845, but with some variations to the test data
        // See http://code.google.com/p/android/issues/detail?id=33845
        assertEquals("No warnings.",

                lintProject(
                        "locale33845/.classpath=>.classpath",
                        "locale33845/AndroidManifest.xml=>AndroidManifest.xml",
                        "locale33845/project.properties=>project.properties",
                        "locale33845/res/values/styles.xml=>res/values/styles.xml",
                        "locale33845/res/values/strings2.xml=>res/values/strings.xml",
                        "locale33845/res/values-en-rGB/strings2.xml=>res/values-en-rGB/strings.xml"
                ));
    }

    public void testEnglishRegionAndValuesAsEnglish1() throws Exception {
        TranslationDetector.sCompleteRegions = false;
        // tools:locale=en in base folder
        // Regression test for https://code.google.com/p/android/issues/detail?id=75879
        assertEquals("No warnings.",

                lintProject(
                        "locale33845/res/values/strings3.xml=>res/values/strings.xml",
                        "locale33845/res/values-en-rGB/strings3.xml=>res/values-en-rGB/strings.xml"
                ));
    }

    public void testEnglishRegionAndValuesAsEnglish2() throws Exception {
        TranslationDetector.sCompleteRegions = false;
        // No tools:locale specified in the base folder: *assume* English
        // Regression test for https://code.google.com/p/android/issues/detail?id=75879
        assertEquals(""
                + "res/values/strings.xml:5: Error: \"other\" is not translated in \"de-DE\" (German: Germany) [MissingTranslation]\n"
                + "    <string name=\"other\">other</string>\n"
                + "            ~~~~~~~~~~~~\n"
                + "1 errors, 0 warnings\n",

                lintProject(
                        "locale33845/res/values/strings4.xml=>res/values/strings.xml",
                        // Flagged because it's not the default locale:
                        "locale33845/res/values-en-rGB/strings3.xml=>res/values-de-rDE/strings.xml",
                        // Not flagged because it's the implicit default locale
                        "locale33845/res/values-en-rGB/strings3.xml=>res/values-en-rGB/strings.xml"
                ));
    }

    public void testEnglishRegionAndValuesAsEnglish3() throws Exception {
        TranslationDetector.sCompleteRegions = false;
        // tools:locale=de in base folder
        // Regression test for https://code.google.com/p/android/issues/detail?id=75879
        assertEquals("No warnings.",

                lintProject(
                        "locale33845/res/values/strings5.xml=>res/values/strings.xml",
                        "locale33845/res/values-en-rGB/strings3.xml=>res/values-de-rDE/strings.xml"
                ));
    }

    public void testResConfigs() throws Exception {
        TranslationDetector.sCompleteRegions = false;
        assertEquals(""
                + "res/values/strings.xml:25: Error: \"menu_settings\" is not translated in \"cs\" (Czech), \"de-DE\" (German: Germany) [MissingTranslation]\n"
                + "    <string name=\"menu_settings\">Settings</string>\n"
                + "            ~~~~~~~~~~~~~~~~~~~~\n"
                + "res/values-cs/arrays.xml:3: Error: \"security_questions\" is translated here but not found in default locale [ExtraTranslation]\n"
                + "  <string-array name=\"security_questions\">\n"
                + "                ~~~~~~~~~~~~~~~~~~~~~~~~~\n"
                + "    res/values-es/strings.xml:12: Also translated here\n"
                + "res/values-de-rDE/strings.xml:11: Error: \"continue_skip_label\" is translated here but not found in default locale [ExtraTranslation]\n"
                + "    <string name=\"continue_skip_label\">\"Weiter\"</string>\n"
                + "            ~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
                + "3 errors, 0 warnings\n",

                lintProject(
                        "res/values/strings.xml",
                        "res/values-cs/strings.xml",
                        "res/values-de-rDE/strings.xml",
                        "res/values-es/strings.xml",
                        "res/values-es-rUS/strings.xml",
                        "res/values-land/strings.xml",
                        "res/values-cs/arrays.xml",
                        "res/values-es/donottranslate.xml",
                        "res/values-nl-rNL/strings.xml"));
    }

    public void testMissingBaseCompletely() throws Exception {
        TranslationDetector.sCompleteRegions = false;
        assertEquals(""
                + "res/values-cs/strings.xml:4: Error: \"home_title\" is translated here but not found in default locale [ExtraTranslation]\n"
                + "    <string name=\"home_title\">\"Domů\"</string>\n"
                + "            ~~~~~~~~~~~~~~~~~\n"
                + "res/values-cs/strings.xml:5: Error: \"show_all_apps\" is translated here but not found in default locale [ExtraTranslation]\n"
                + "    <string name=\"show_all_apps\">\"Vše\"</string>\n"
                + "            ~~~~~~~~~~~~~~~~~~~~\n"
                + "res/values-cs/strings.xml:6: Error: \"menu_wallpaper\" is translated here but not found in default locale [ExtraTranslation]\n"
                + "    <string name=\"menu_wallpaper\">\"Tapeta\"</string>\n"
                + "            ~~~~~~~~~~~~~~~~~~~~~\n"
                + "res/values-cs/strings.xml:7: Error: \"menu_search\" is translated here but not found in default locale [ExtraTranslation]\n"
                + "    <string name=\"menu_search\">\"Hledat\"</string>\n"
                + "            ~~~~~~~~~~~~~~~~~~\n"
                + "res/values-cs/strings.xml:10: Error: \"wallpaper_instructions\" is translated here but not found in default locale [ExtraTranslation]\n"
                + "    <string name=\"wallpaper_instructions\">\"Klepnutím na obrázek nastavíte tapetu portrétu\"</string>\n"
                + "            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
                + "5 errors, 0 warnings\n",

                lintProject("res/values-cs/strings.xml"));
    }

    public void testMissingSomeBaseStrings() throws Exception {
        TranslationDetector.sCompleteRegions = false;
        assertEquals(""
                + "res/values-es/strings.xml:4: Error: \"home_title\" is translated here but not found in default locale [ExtraTranslation]\n"
                + "    <string name=\"home_title\">\"Casa\"</string>\n"
                + "            ~~~~~~~~~~~~~~~~~\n"
                + "res/values-es/strings.xml:5: Error: \"show_all_apps\" is translated here but not found in default locale [ExtraTranslation]\n"
                + "    <string name=\"show_all_apps\">\"Todo\"</string>\n"
                + "            ~~~~~~~~~~~~~~~~~~~~\n"
                + "res/values-es/strings.xml:6: Error: \"menu_wallpaper\" is translated here but not found in default locale [ExtraTranslation]\n"
                + "    <string name=\"menu_wallpaper\">\"Papel tapiz\"</string>\n"
                + "            ~~~~~~~~~~~~~~~~~~~~~\n"
                + "res/values-es/strings.xml:10: Error: \"wallpaper_instructions\" is translated here but not found in default locale [ExtraTranslation]\n"
                + "    <string name=\"wallpaper_instructions\">\"Puntee en la imagen para establecer papel tapiz vertical\"</string>\n"
                + "            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
                + "res/values-es/strings.xml:12: Error: \"security_questions\" is translated here but not found in default locale [ExtraTranslation]\n"
                + "  <string-array name=\"security_questions\">\n"
                + "                ~~~~~~~~~~~~~~~~~~~~~~~~~\n"
                + "5 errors, 0 warnings\n",

                lintProject(
                        "res/values-es-rUS/strings.xml=>res/values/strings.xml",
                        "res/values-es/strings.xml=>res/values-es/strings.xml"

                ));
    }

    public void testConfigKeys() throws Exception {
        // Some developer services create config files merged with your project, but in some
        // versions they were missing a translatable="false" entry. Since we know these aren't
        // keys you normally want to translate, let's filter them for users.
        TranslationDetector.sCompleteRegions = false;
        assertEquals("No warnings.",
                lintProject(
                        xml("res/values/config.xml", ""
                                + "<resources>\n"
                                + "    <string name=\"gcm_defaultSenderId\">SENDER_ID</string>\n"
                                + "    <string name=\"google_app_id\">App Id</string>\n"
                                + "    <string name=\"ga_trackingID\">Analytics</string>\n"
                                + "</resources>\n"),
                        xml("res/values/strings.xml", ""
                                + "<resources>\n"
                                + "    <string name=\"app_name\">My Application</string>\n"
                                + "</resources>\n"),
                        xml("res/values-nb/strings.xml", ""
                                + "<resources>\n"
                                + "    <string name=\"app_name\">Min Applikasjon</string>\n"
                                + "</resources>\n")
                ));
    }

    @Override
    protected TestLintClient createClient() {
        if (!getName().startsWith("testResConfigs")) {
            return super.createClient();
        }

        // Set up a mock project model for the resource configuration test(s)
        // where we provide a subset of densities to be included

        return new TestLintClient() {
            @NonNull
            @Override
            protected Project createProject(@NonNull File dir, @NonNull File referenceDir) {
                return new Project(this, dir, referenceDir) {
                    @Override
                    public boolean isGradleProject() {
                        return true;
                    }

                    @Nullable
                    @Override
                    public AndroidProject getGradleProjectModel() {
                        /*
                        Simulate variant freeBetaDebug in this setup:
                            defaultConfig {
                                ...
                                resConfigs "cs"
                            }
                            flavorDimensions  "pricing", "releaseType"
                            productFlavors {
                                beta {
                                    flavorDimension "releaseType"
                                    resConfig "en", "de"
                                    resConfigs "nodpi", "hdpi"
                                }
                                normal { flavorDimension "releaseType" }
                                free { flavorDimension "pricing" }
                                paid { flavorDimension "pricing" }
                            }
                         */
                        ProductFlavor flavorFree = mock(ProductFlavor.class);
                        when(flavorFree.getName()).thenReturn("free");
                        when(flavorFree.getResourceConfigurations())
                                .thenReturn(Collections.<String>emptyList());

                        ProductFlavor flavorNormal = mock(ProductFlavor.class);
                        when(flavorNormal.getName()).thenReturn("normal");
                        when(flavorNormal.getResourceConfigurations())
                                .thenReturn(Collections.<String>emptyList());

                        ProductFlavor flavorPaid = mock(ProductFlavor.class);
                        when(flavorPaid.getName()).thenReturn("paid");
                        when(flavorPaid.getResourceConfigurations())
                                .thenReturn(Collections.<String>emptyList());

                        ProductFlavor flavorBeta = mock(ProductFlavor.class);
                        when(flavorBeta.getName()).thenReturn("beta");
                        List<String> resConfigs = Arrays.asList("hdpi", "en", "de", "nodpi");
                        when(flavorBeta.getResourceConfigurations()).thenReturn(resConfigs);

                        ProductFlavor defaultFlavor = mock(ProductFlavor.class);
                        when(defaultFlavor.getName()).thenReturn("main");
                        when(defaultFlavor.getResourceConfigurations()).thenReturn(
                                Collections.singleton("cs"));

                        ProductFlavorContainer containerBeta =
                                mock(ProductFlavorContainer.class);
                        when(containerBeta.getProductFlavor()).thenReturn(flavorBeta);

                        ProductFlavorContainer containerFree =
                                mock(ProductFlavorContainer.class);
                        when(containerFree.getProductFlavor()).thenReturn(flavorFree);

                        ProductFlavorContainer containerPaid =
                                mock(ProductFlavorContainer.class);
                        when(containerPaid.getProductFlavor()).thenReturn(flavorPaid);

                        ProductFlavorContainer containerNormal =
                                mock(ProductFlavorContainer.class);
                        when(containerNormal.getProductFlavor()).thenReturn(flavorNormal);

                        ProductFlavorContainer defaultContainer =
                                mock(ProductFlavorContainer.class);
                        when(defaultContainer.getProductFlavor()).thenReturn(defaultFlavor);

                        List<ProductFlavorContainer> containers = Arrays.asList(
                                containerPaid, containerFree, containerNormal, containerBeta
                        );

                        AndroidProject project = mock(AndroidProject.class);
                        when(project.getProductFlavors()).thenReturn(containers);
                        when(project.getDefaultConfig()).thenReturn(defaultContainer);
                        return project;
                    }

                    @Nullable
                    @Override
                    public Variant getCurrentVariant() {
                        List<String> productFlavorNames = Arrays.asList("free", "beta");
                        Variant mock = mock(Variant.class);
                        when(mock.getProductFlavors()).thenReturn(productFlavorNames);
                        return mock;
                    }
                };
            }
        };
    }
}
