package utils; import static io.sphere.internal.filters.DynamicFilterHelpers.*; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.anyVararg; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import io.sphere.client.ProductSort; import io.sphere.client.facets.expressions.FacetExpression; import io.sphere.client.filters.expressions.FilterExpression; import io.sphere.client.model.Money; import io.sphere.client.model.SearchResult; import io.sphere.client.model.VersionedId; import io.sphere.client.model.facets.FacetResult; import io.sphere.client.model.facets.RangeFacetItem; import io.sphere.client.model.facets.RangeFacetResultRaw; import io.sphere.client.shop.CategoryTree; import io.sphere.client.shop.model.Attribute; import io.sphere.client.shop.model.Cart; import io.sphere.client.shop.model.CartUpdate; import io.sphere.client.shop.model.Category; import io.sphere.client.shop.model.Dimensions; import io.sphere.client.shop.model.Image; import io.sphere.client.shop.model.LineItem; import io.sphere.client.shop.model.Price; import io.sphere.client.shop.model.Product; import io.sphere.client.shop.model.Variant; import io.sphere.client.shop.model.VariantList; import java.lang.reflect.Field; import java.math.BigDecimal; import java.util.*; import org.joda.time.DateTime; import sphere.CurrentCart; import sphere.FetchRequest; import sphere.ProductService; import sphere.SearchRequest; import sphere.Sphere; import com.google.common.base.Optional; import com.neovisionaries.i18n.CountryCode; public class SphereTestable { private final Sphere sphere; public SearchRequest searchRequest; public CategoryTree categoryTree; public CurrentCart currentCart; public static String currency = "EUR"; public static CountryCode country = CountryCode.DE; public static Locale locale = Locale.ENGLISH; public SphereTestable() { sphere = mock(Sphere.class); mockCategoryTree(Collections.<Category> emptyList()); mockProductService(Collections.<Product> emptyList(), 0, 100); mockCurrentCart(Collections.<LineItem> emptyList()); setSphereInstance(sphere); } public void mockCurrentCart(List<LineItem> items) { CurrentCart currentCart = mock(CurrentCart.class); // Mock fetch Cart cart = mockCart(items); when(currentCart.fetch()).thenReturn(cart); // Mock quantity when(currentCart.getQuantity()).thenReturn(items.size()); // Mock add item when(currentCart.addLineItem(anyString(), anyInt())).thenReturn(cart); when(currentCart.addLineItem(anyString(), anyInt(), anyInt())).thenReturn(cart); // Mock remove item when(currentCart.removeLineItem(anyString())).thenReturn(cart); // Mock update cart when(currentCart.update(any(CartUpdate.class))).thenReturn(cart); this.currentCart = currentCart; when(sphere.currentCart()).thenReturn(currentCart); setSphereInstance(sphere); } public void mockCategoryTree(List<Category> categories) { CategoryTree categoryTree = mock(CategoryTree.class); // Mock get list when(categoryTree.getAsFlatList()).thenReturn(categories); // Mock get by id/slug List<Category> roots = new ArrayList<Category>(); for (Category c : categories) { when(categoryTree.getBySlug(c.getSlug())).thenReturn(c); when(categoryTree.getById(c.getId())).thenReturn(c); if (c.isRoot()) roots.add(c); } // Mock get roots when(categoryTree.getRoots()).thenReturn(roots); this.categoryTree = categoryTree; when(sphere.categories()).thenReturn(categoryTree); setSphereInstance(sphere); } @SuppressWarnings("unchecked") public void mockProductService(List<Product> products, int page, int pageSize) { ProductService productService = mock(ProductService.class); // Mock get all SearchRequest<Product> searchRequest = mockSearchRequest(products, page, pageSize); when(productService.all()).thenReturn(searchRequest); // Mock filter when(productService.filter(any(FilterExpression.class))).thenReturn(searchRequest); when(productService.filter(any(Iterable.class))).thenReturn(searchRequest); // Mock get by id/slug // when(productService.byId(anyString())).thenReturn(mockFetchRequest(null)); // when(productService.bySlug(anyString())).thenReturn(mockFetchRequest(null)); for (Product p : products) { FetchRequest<Product> fetchRequest = mockFetchRequest(p); when(productService.byId(p.getId())).thenReturn(fetchRequest); when(productService.bySlug(p.getSlug())).thenReturn(fetchRequest); } when(sphere.products()).thenReturn(productService); setSphereInstance(sphere); } public static List<Category> mockCategory(String name, int level) { List<Category> categories = new ArrayList<Category>(); List<Category> tree = new ArrayList<Category>(); for (int i = 0; i < level; ++i) { Category category = mockCategoryNode(name, tree); categories.add(category); if (!tree.isEmpty()) { when(tree.get(tree.size() - 1).getChildren()).thenReturn(Collections.singletonList(category)); } tree.add(category); } return categories; } public static Product mockProduct(String name, int numVariants, int numAttributes, int numImages) { Product product = mock(Product.class); // Mock id/name/slug when(product.getId()).thenReturn(name+"Id"); when(product.getIdAndVersion()).thenReturn(VersionedId.create(name, 1)); when(product.getSlug()).thenReturn(name+"Slug"); when(product.getName()).thenReturn(name); // Mock price when(product.getPrice()).thenReturn(mockPrice(10)); // Mock image Image image = mockImage(); when(product.getFeaturedImage()).thenReturn(image); when(product.getImages()).thenReturn(Collections.nCopies(numImages, image)); // Mock attribute Attribute attribute = mockAttribute("attrName", "attrValue"); when(product.get(anyString())).thenReturn(attribute); when(product.getString(anyString())).thenReturn("attrValue"); when(product.getInt(anyString())).thenReturn(5); when(product.getMoney(anyString())).thenReturn(mockMoney(5)); when(product.getDouble(anyString())).thenReturn(5.0); when(product.getAttribute(anyString())).thenReturn(attribute); when(product.getAttributes()).thenReturn(Collections.nCopies(numAttributes, attribute)); // Mock variants List<Variant> variantList = new ArrayList<Variant>(); for (int i = 0; i < numVariants + 1; ++i) { variantList.add(mockVariant(i)); } when(product.getVariants()).thenReturn(new VariantList(variantList)); // Mock master variant when(product.getMasterVariant()).thenReturn(variantList.get(0)); return product; } public static Variant mockVariant(int id) { Variant variant = mock(Variant.class); // Mock get id when(variant.getId()).thenReturn(id); // Mock get attributes when(variant.get(anyString())).thenReturn("attrValue"); // Mock get price when(variant.getPrice()).thenReturn(mockPrice(10)); // Mock get images Image image = mockImage(); when(variant.getFeaturedImage()).thenReturn(image); when(variant.getImages()).thenReturn(Collections.singletonList(image)); return variant; } public Cart mockCart(List<LineItem> items) { Cart cart = mock(Cart.class); // Mock id/version String id = UUID.randomUUID().toString(); when(cart.getId()).thenReturn(id); when(cart.getIdAndVersion()).thenReturn(VersionedId.create(id, 1)); // Mock state/inventory when(cart.getCartState()).thenReturn(Cart.CartState.Active); when(cart.getInventoryMode()).thenReturn(Cart.InventoryMode.None); // Mock country/currency when(cart.getCountry()).thenReturn(country); when(cart.getCurrency()).thenReturn(Currency.getInstance(currency)); // Mock line items when(cart.getLineItems()).thenReturn(items); // Mock total price double amount = 0; for (LineItem item : items) { amount += item.getTotalPrice().getAmount().doubleValue(); } when(cart.getTotalPrice()).thenReturn(mockMoney(amount)); // Mock quantity when(cart.getTotalQuantity()).thenReturn(items.size()); // Mock time when(cart.getLastModifiedAt()).thenReturn(DateTime.now()); when(cart.getCreatedAt()).thenReturn(DateTime.now()); return cart; } public LineItem mockLineItem(String name, int quantity) { LineItem item = mock(LineItem.class); // Mock id/name when(item.getId()).thenReturn(name); when(item.getProductId()).thenReturn(name); when(item.getProductName()).thenReturn(name); // Mock variant when(item.getVariant()).thenReturn(mockVariant(1)); // Mock quantity when(item.getQuantity()).thenReturn(quantity); // Mock price double amount = 10; when(item.getPrice()).thenReturn(mockPrice(amount)); when(item.getTotalPrice()).thenReturn(mockMoney(amount * quantity)); return item; } @SuppressWarnings("unchecked") private SearchRequest<Product> mockSearchRequest(List<Product> products, int page, int pageSize) { SearchRequest<Product> request = mock(SearchRequest.class); // Mock request filter when(request.filter(any(FilterExpression.class))).thenReturn(request); when(request.filter(any(Iterable.class))).thenReturn(request); // Mock request facet when(request.facet(any(FacetExpression.class))).thenReturn(request); when(request.facet(any(Collection.class))).thenReturn(request); // Mock request sort when(request.sort(any(ProductSort.class))).thenReturn(request); // Mock request paging when(request.page(anyInt())).thenReturn(request); when(request.pageSize(anyInt())).thenReturn(request); // Mock request fetch int total = products.size(); int offset = page * pageSize; int count = Math.min(total - offset, pageSize); List<Product> result = new ArrayList<Product>(); if (count > 0) result = products.subList(0, count); // Mock facet results Map<String, FacetResult> facetResult = new HashMap<String, FacetResult>(); facetResult.put(PriceRangeFilterExpression.helperFacetAlias, mockFacetRangeResult(300, 9000)); SearchResult<Product> searchResult = new SearchResult<Product>(offset, count, total, result, facetResult, pageSize); when(request.fetch()).thenReturn(searchResult); this.searchRequest = request; return request; } private FacetResult mockFacetRangeResult(double min, double max) { RangeFacetItem rangeItem = mock(RangeFacetItem.class); when(rangeItem.getMin()).thenReturn(min); when(rangeItem.getMax()).thenReturn(max); return new RangeFacetResultRaw(Collections.singletonList(rangeItem)); } @SuppressWarnings("unchecked") private FetchRequest<Product> mockFetchRequest(Product product) { FetchRequest<Product> request = mock(FetchRequest.class); // Mock request expand when(request.expand((String) anyVararg())).thenReturn(request); // Mock request fetch when(request.fetch()).thenReturn(Optional.of(product)); return request; } private static Image mockImage() { return new Image("image.png", "imageLabel", new Dimensions(1000, 1000)); } private static Attribute mockAttribute(String name, String value) { return new Attribute(name, value); } private static Money mockMoney(double amount) { return new Money(BigDecimal.valueOf(amount), currency); } private static Price mockPrice(double amount) { return new Price(mockMoney(amount), country, null); } private static Category mockCategoryNode(String prefix, List<Category> ancestors) { Category category = mock(Category.class); int level = ancestors.size() + 1; when(category.getId()).thenReturn(prefix+level+"Id"); when(category.getName()).thenReturn(prefix+level+"Name"); when(category.getSlug()).thenReturn(prefix+level+"Slug"); when(category.getDescription()).thenReturn(prefix+level+"Description"); // Mock root when(category.isRoot()).thenReturn(level < 2); // Mock parent Category parent = null; if (level > 1) { parent = ancestors.get(ancestors.size() - 1); } when(category.getParent()).thenReturn(parent); // Mock category tree List<Category> categoryTree = new ArrayList<Category>(ancestors); when(category.getPathInTree()).thenReturn(categoryTree); categoryTree.add(category); return category; } private static void setSphereInstance(Sphere sphere) { try { Field field = Sphere.class.getDeclaredField("instance"); field.setAccessible(true); field.set(null, sphere); } catch (Throwable t) { t.printStackTrace(); } } }