package io.sphere.sdk.facets; import io.sphere.sdk.categories.Category; import io.sphere.sdk.json.SphereJsonUtils; import org.junit.Test; import javax.annotation.Nullable; import java.util.List; import java.util.Locale; import java.util.Optional; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; import static java.util.Locale.GERMAN; import static org.assertj.core.api.Assertions.assertThat; public class HierarchicalCategoryFacetOptionMapperTest { private static final List<Locale> LOCALES = singletonList(Locale.ENGLISH); private final static String CAT_A_ID = "d5a0952b-6574-49c9-b0cd-61e0d21d36cc"; private final static String CAT_B_ID = "e92b6d26-7a34-4960-804c-0fc9e40c64e3"; private final static String CAT_C_ID = "1acce167-cd23-4fd7-b344-af76941cb375"; private final static String CAT_D_ID = "f5b288e8-d19c-4c0d-a18a-8ca68f982b8e"; private final static String CAT_E_ID = "b00b1eb9-f051-4f13-8f9c-1bb73e13e8a1"; private static final Category CAT_A = category(CAT_A_ID, null, "A"); private static final Category CAT_B = category(CAT_B_ID, CAT_A_ID, "B"); private static final Category CAT_C = category(CAT_C_ID, CAT_B_ID, "C"); private static final Category CAT_D = category(CAT_D_ID, CAT_B_ID, "D"); private static final Category CAT_E = category(CAT_E_ID, CAT_A_ID, "E"); private static final FacetOption OPTION_A = FacetOption.of(CAT_A_ID, 0, false); private static final FacetOption OPTION_B = FacetOption.of(CAT_B_ID, 1, false); private static final FacetOption OPTION_C = FacetOption.of(CAT_C_ID, 2, true); private static final FacetOption OPTION_D = FacetOption.of(CAT_D_ID, 3, false); /* A * |-- B * | |-- C * | |-- D * | * |-- E */ @Test public void replacesIdForName() throws Exception { final List<Category> subcategories = singletonList(CAT_D); final List<FacetOption> hierarchicalOptions = HierarchicalCategoryFacetOptionMapper.of(subcategories, LOCALES) .apply(singletonList(OPTION_D)); assertThat(hierarchicalOptions).containsExactly(OPTION_D.withLabel("D")); } @Test public void keepsOrderFromCategoryTree() throws Exception { final List<Category> subcategories = asList(CAT_C, CAT_D); final List<FacetOption> hierarchicalOptions = HierarchicalCategoryFacetOptionMapper.of(subcategories, LOCALES) .apply(asList(OPTION_D, OPTION_C)); assertThat(hierarchicalOptions).containsExactly(OPTION_C.withLabel("C"), OPTION_D.withLabel("D")); } @Test public void discardsOnMissingLocale() throws Exception { final List<Category> subcategories = singletonList(CAT_D); final List<FacetOption> hierarchicalOptions = HierarchicalCategoryFacetOptionMapper.of(subcategories, singletonList(GERMAN)) .apply(singletonList(OPTION_D)); assertThat(hierarchicalOptions).isEmpty(); } @Test public void discardsWithEmptyCategoryTree() throws Exception { final List<Category> subcategories = emptyList(); final List<FacetOption> hierarchicalOptions = HierarchicalCategoryFacetOptionMapper.of(subcategories, LOCALES) .apply(asList(OPTION_D, OPTION_C)); assertThat(hierarchicalOptions).isEmpty(); } @Test public void worksWithEmptyFacetOptions() throws Exception { final List<Category> subcategories = singletonList(CAT_D); final List<FacetOption> hierarchicalOptions = HierarchicalCategoryFacetOptionMapper.of(subcategories, LOCALES) .apply(emptyList()); assertThat(hierarchicalOptions).isEmpty(); } @Test public void inheritsInformationFromLeaves() throws Exception { final List<Category> subcategories = asList(CAT_B, CAT_C, CAT_D); final List<FacetOption> hierarchicalOptions = HierarchicalCategoryFacetOptionMapper.of(subcategories, LOCALES) .apply(asList(OPTION_D, OPTION_C, OPTION_B)); final FacetOption expectedOptions = OPTION_B .withLabel("B") .withCount(sumCount(OPTION_B, OPTION_C, OPTION_D)) .withSelected(isAnySelected(OPTION_B, OPTION_C, OPTION_D)) .withChildren(asList(OPTION_C.withLabel("C"), OPTION_D.withLabel("D"))); assertThat(hierarchicalOptions).containsExactly(expectedOptions); } @Test public void discardsEmptyBranches() throws Exception { final List<Category> subcategories = asList(CAT_A, CAT_B, CAT_C, CAT_D, CAT_E); final List<FacetOption> hierarchicalOptions = HierarchicalCategoryFacetOptionMapper.of(subcategories, LOCALES) .apply(asList(OPTION_D, OPTION_C, OPTION_B)); final FacetOption expectedOptions = OPTION_A .withLabel("A") .withCount(sumCount(OPTION_A, OPTION_B, OPTION_C, OPTION_D)) .withSelected(isAnySelected(OPTION_A, OPTION_B, OPTION_C, OPTION_D)) .withChildren(singletonList(OPTION_B .withLabel("B") .withCount(sumCount(OPTION_B, OPTION_C, OPTION_D)) .withSelected(isAnySelected(OPTION_B, OPTION_C, OPTION_D)) .withChildren(asList(OPTION_C.withLabel("C"), OPTION_D.withLabel("D"))))); assertThat(hierarchicalOptions).containsExactly(expectedOptions); } private long sumCount(final FacetOption... facetOptions) { return asList(facetOptions).stream().mapToLong(FacetOption::getCount).sum(); } private boolean isAnySelected(final FacetOption... facetOptions) { return asList(facetOptions).stream().anyMatch(FacetOption::isSelected); } private static Category category(final String id, @Nullable final String parentId, final String name) { final String parentJson = Optional.ofNullable(parentId).map(p -> " \"parent\": {" + " \"typeId\": \"category\"," + " \"id\": \""+ p +"\"" + " },").orElse(""); final String json = "{" + " \"id\": \"" + id + "\"," + " \"version\": 1," + parentJson + " \"name\": {" + " \"en\": \"" + name + "\"" + " }," + " \"slug\": {" + " \"en\": \"" + name + "-slug\"" + " }" + "}"; return SphereJsonUtils.readObject(json, Category.typeReference()); } }