def test_findSize(self): # Given sut = Product() sizeA = Size(sizeEU="41.25") sizeB = Size(sizeEU="38 2/3") sizeC = Size(sizeEU="39") sut.addSize(sizeA) sut.addSize(sizeB) sut.addSize(sizeC) # When given size not exists foundSize = sut.findSize(sizeStr="45") # Then self.assertIsNone(foundSize, f"Expected that size was not found and " f"returned value is None, but got '{foundSize}'") # When foundSize = sut.findSize(sizeStr=sizeA.sizeEU) # Then self.assertEqual(sizeA, foundSize) # When foundSize = sut.findSize(sizeStr=sizeB.sizeEU) # Then self.assertEqual(sizeB, foundSize) # When foundSize = sut.findSize(sizeStr=sizeC.sizeEU) # Then self.assertEqual(sizeC, foundSize)
def _decodeProducts(cls, productItems: list) -> List[Product]: decodedProducts: List[Product] = list() for productItem in productItems: product = Product(**productItem) product.sizes = cls._decodeSizes(product.sizes) decodedProducts.append(product) return decodedProducts
async def _setProductPrice(self, soup: BeautifulSoup, product: Product) -> ProductChanged: isProductChanged = False try: thisProductInfo = soup.find("div", class_="b-pdp-product-info-section") priceElem = thisProductInfo.find( "span", class_="b-product-tile-price-item") priceAndCurrencyStr = priceElem.text.strip() # like '98,55 €' # Split price and currency match = re.search(r"(([0-9.,]+)\s+([^0-9]+))", priceAndCurrencyStr) priceStr, currencyStr = match.group(2), match.group(3) priceFloat = float(priceStr.replace(",", ".")) except Exception as e: logger.warning("Failed finding product price or currency. %s. %s", e, product.url) self._failCount += 1 else: logger.debug( "Extracted product price & currency from HTML code. %s", product.url) if not product.basePrice or product.basePrice != priceFloat: product.basePrice = priceFloat product.currency = currencyStr isProductChanged = True # note that we never switch back to False finally: return isProductChanged
def run_homework(): cookie = Product(name="Ciastko", category_name="Jedzenie", unit_price=4) # other_cookie = Product(name="Inne ciastko", category_name="Jedzenie", unit_price=4) juice = Product(name="Sok", category_name="Napoje", unit_price=3) first_order_elements = [ OrderElement(product=cookie, quantity=3), # OrderElement(product=other_cookie, quantity=3), OrderElement(product=juice, quantity=4), ] # first_order_elements.append(OrderElement(product=juice, quantity=4)) # first_order_elements[0].quantity = 10 second_order_elements = [ OrderElement(product=juice, quantity=4), OrderElement(product=cookie, quantity=3), ] first_order = Order(client_first_name="Kuba", client_last_name="Kowalski", order_elements=first_order_elements) second_order = Order(client_first_name="Kuba", client_last_name="Kowalski", order_elements=second_order_elements) # second_order.client_last_name = "Lewandowski" if first_order == second_order: print("Te zamówienia są takie same!") else: print("Te zamówienia są różne!")
def run_homework(): product_one = Product(name="Cookies", category_name="Food", unit_price=3.5) product_two = Product(name="Cheese", category_name="Food", unit_price=3.5) product_three = Product(name="Cookies", category_name="Food", unit_price=3.5) print(f"Products 1 and 2 are equal? {product_one == product_two}") print(f"Products 1 and 3 are equal? {product_one == product_three}") print(f"Products 2 and 3 are equal? {product_two == product_three}") order_element_1 = OrderElement(product_one, 3) order_element_2 = OrderElement(product_one, 3) order_element_3 = OrderElement(product_two, 4) print( f"Order elements 1 and 2 are equal? {order_element_1 == order_element_2}" ) print( f"Order elements 1 and 3 are equal? {order_element_1 == order_element_3}" ) print( f"Order elements 2 and 3 are equal? {order_element_2 == order_element_3}" ) order_1 = Order(client_first_name="Maciej", client_last_name="Sobieszuk", order_elements=[order_element_1, order_element_2]) order_2 = Order(client_first_name="Maciej", client_last_name="Sobieszuk", order_elements=[order_element_2, order_element_1]) order_3 = Order(client_first_name="Maciej", client_last_name="Xyz", order_elements=[order_element_1, order_element_2]) print(f"Orders 1 and 2 are equal? {order_1 == order_2}") print(f"Orders 1 and 3 are equal? {order_1 == order_3}") print(f"Orders 2 and 3 are equal? {order_2 == order_3}")
def test_lastScanStamp_shouldGetAndSet(self): # Given sut = Product() # When Setter sut.lastScanStamp = 123456789.987654321 # Then Getter self.assertEqual(123456789.987654321, sut.lastScanStamp)
def test_addSize_shouldRaiseTypeErrorOnInvalidType(self): # Given sut = Product() invalidType = mock.Mock(spec=dict) # When / Then with self.assertRaises(TypeError): sut.addSize(invalidType)
def test_url_shouldGetAndSet(self): # Given sut = Product() # When Setter sut.url = "https://something-to-test/shop" # Then Getter self.assertEqual("https://something-to-test/shop", sut.url)
def test_name_shouldGetAndSet(self): # Given sut = Product() # When Setter sut.name = "My smart product" # Then Getter self.assertEqual("My smart product", sut.name)
def test_getReleaseDate_shouldReturnNoneWhenReleaseStampIsNotSet(self): # Given sut = Product() sut.invalidateReleaseDate() # When result = sut.getReleaseDate(forTimezone="America/Indiana/Petersburg", forType=dtt.datetime) # Then self.assertEqual(None, result)
def test_sizes_setterShouldRaiseOnInvalidType(self): # Given sut = Product() sizeA = mock.Mock(spec=Size) invalidType = mock.Mock() invalidList = [sizeA, invalidType] # When / Then with self.assertRaises(TypeError): sut.sizes = invalidList
def test_getReleaseDate_shouldReturnReadableString(self): # Given sut = Product() givenDatetime = dtt.datetime(2023, 11, 28, 13, 30, 12) givenTimezoneString = "Europe/Berlin" # See also: pytz.all_timezones expectedString = "28.11.2023, 13:30:12" sut.setReleaseDate(givenDatetime, timezone=givenTimezoneString) # When result = sut.getReleaseDate(forTimezone=givenTimezoneString, forType=str) # Then self.assertEqual(expectedString, result)
def run_homework(): cookie = Product(name="Ciastko", category_name="Jedzenie", unit_price=4) tomato = Product(name="Pomidor", category_name="Owoce i warzywa", unit_price=3) something = Product(name="Coś", category_name="Nieznana kategoria", unit_price=50) ten_cookies = OrderElement(cookie, quantity=10) five_tomatoes = OrderElement(tomato, quantity=5) single_something = OrderElement(something, quantity=1) cookies_tax = TaxCalculator.tax_for_order_element(ten_cookies) tomatoes_tax = TaxCalculator.tax_for_order_element(five_tomatoes) something_tax = TaxCalculator.tax_for_order_element(single_something) print(f"Cena ciastek: {ten_cookies.calculate_price()} + {cookies_tax:.2f}") print(f"Cena pomidorów: {five_tomatoes.calculate_price()} + {tomatoes_tax:.2f}") print(f"Cena czegoś: {single_something.calculate_price()} + {something_tax:.2f}")
async def _setProductThumbUrl(self, soup: BeautifulSoup, product: Product) -> ProductChanged: isProductChanged = False try: urlThumb = soup.find("li", class_="thumbnail-1") \ .find("div", class_="wrap") \ .img["src"] # Below code possibly superfluous. The above urlThumb is already valid, # but for mighty reasons linking to it in Discord seems to get blocked by BSTN. There's # a way to shorten the URL, as the last parts of the URL don't seem to be relevant. # Anyway, this won't fix the blocked link in Discord. # Example # https://www.bstn.com/media/140801/w/280/h/280/n/adidas-zx-8000-fv3269-1.jpg # is converted to # https://www.bstn.com/media/140801/w/280/h/280/n/0.jpg # match = re.search(r".*/h/280/n/", urlThumb) # urlThumb = f"{match.group()}0.jpg" if not urlThumb: raise AttributeError("No matches in HTML tree.") except AttributeError as e: logger.warning("Failed finding product image url. %s. %s", e, product.url) self._failCount += 1 else: logger.debug("Found product image url. %s", product.url) if not product.urlThumb or product.urlThumb != urlThumb: product.urlThumb = urlThumb isProductChanged = True # note that we never switch back to False finally: return isProductChanged
def test_product_eq(): parameters = [ ("Banan", "Owoc", 2, "Ananas", "Owoc", 4, False), ("Stek", "Mięso", 50, "Yaris", "Auto", 10000, False), ("Yaris", "Auto", 10000, "Yaris", "Auto", 10000, True), ("Banan", "Owoc", 2, "Ananas", "Owoc", 4, True) ] for params in parameters: name, category_name, unit_price, other_name, other_category_name, other_unit_price, expected_result = params result = Product(name, category_name, unit_price, Product.identifier) == \ Product(other_name, other_category_name, other_unit_price, Product.identifier) if result == expected_result: print("Super!") else: print(f"Błąd! Dla danych {params} wynik powinen wynosić {expected_result} a wynosi {result}.")
async def _setProductThumbUrl(self, soup: BeautifulSoup, product: Product) -> ProductChanged: isProductChanged = False try: urlThumb = soup.find("div", class_="thumbnail-1") \ .find("div", class_="wrap") \ .img["src"] if not urlThumb: raise AttributeError("No matches in HTML tree.") except AttributeError as e: logger.warning("Failed finding product image url. %s. %s", e, product.url) self._failCount += 1 else: logger.debug("Found product image url. %s", product.url) # Their image URL is relative so we have to concat the shop's base URL with it. absoluteImageURL = urllib.parse.urljoin(self.URL, urlThumb) if not product.urlThumb or product.urlThumb != absoluteImageURL: product.urlThumb = absoluteImageURL isProductChanged = True # note that we never switch back to False finally: return isProductChanged
def test_run(self): # Given shop = Shop(name="Sneak-a-venue Shop unit test", url=str(self.shopHtmlResponsePath)) product = Product(url=str(self.productHtmlResponsePath)) shop.addProduct(product) # Results will be written to a temp DB file which path is defined in TempShopRepoHelper. repoHelper = TempShopRepoHelper(shops=[shop]) async def runner(): # Given requestMock = RequestMock() messengerMock = MessengerMock(request=requestMock) sut = SneakAvenueShopScraper(scrapee=shop, scrapeeRepo=repoHelper.shopRepo, request=requestMock, messenger=messengerMock) # When / Then try: await sut.run() except Exception as e: self.fail( f"Expected test to run without Exception, but raised: {e}") else: self.assertEqual( 0, sut._failCount, f"Expected fail count to be 0, but is {sut._failCount}") asyncio.run(runner())
def load_orders(client_first_name, client_last_name, file_name="orders.json"): try: with open(file_name, "r") as orders_file: orders_by_clients_data = json.load(orders_file).get("orders", {}) except FileNotFoundError: orders_by_clients_data = {} client_id = f"{client_first_name}-{client_last_name}" if client_id not in orders_by_clients_data: return [] orders = orders_by_clients_data[client_id] return [ Order( client_first_name=order["client_first_name"], client_last_name=order["client_last_name"], order_elements=[ OrderElement( quantity=order_element["quantity"], product=Product( name=order_element["product"]["name"], category=ProductCategory[order_element["product"] ["category"]], unit_price=order_element["product"]["unit_price"], identifier=order_element["product"]["identifier"], )) for order_element in order["order_elements"] ], ) for order in orders ]
def run_homework(): first_order = generate_order() print(first_order) cookies = Product(name="Cookies", category_name="Food", unit_price=5) first_order.add_product_to_order(cookies, quantity=10) print(first_order)
async def _setProductThumbUrl(self, soup: BeautifulSoup, product: Product) -> ProductChanged: """ Search for the following JS code and extract URL: <div class="more-views mobilehidden"> <ul> <li> <a href="https:// ... """ isProductChanged = False try: urlThumb = soup.find("div", {"class": "product-img-box"}) \ .find("div", {"class": "more-views mobilehidden"}) \ .find_next("a").get("href") except AttributeError as e: logger.warning("Failed finding product image url. %s. %s", e, product.url) self._failCount += 1 else: logger.debug("Found product image url. %s", product.url) if not product.urlThumb or product.urlThumb != urlThumb: product.urlThumb = urlThumb isProductChanged = True # note that we never switch back to False finally: return isProductChanged
def run_homework(): first_order = generate_order() print(first_order) cookie = Product(name="Ciastko", category_name="Jedzenie", unit_price=4) first_order.add_product_to_order(cookie, quantity=10) print(first_order)
def test_product_comparision(): parameters = [ ("Ciastka", "Jedzenie", 4, "Ciastka", "Jedzenie", 4, True), ("Ciastka", "Jedzenie", 4, "Chleb", "Jedzenie", 4, False), ("Ciastka", "Jedzenie", 4, "Ciastka", "Słodycze", 4, False), ("Ciastka", "Jedzenie", 4, "Ciastka", "Jedzenie", 8, False), ] for params in parameters: name, category, price, other_name, other_category, other_price, expected_result = params result = Product(name, category, price) == Product(other_name, other_category, other_price) if result == expected_result: print("OK") else: print(f"Błąd! Dla danych {params} wynik porównania jest {result} a powinien być {expected_result}")
def test_sizes_setterShouldSetCorrectValues(self): # Given sut = Product() sizeA = mock.Mock(spec=Size) sizeB = mock.Mock(spec=Size) sizeC = mock.Mock(spec=Size) sizeA.mockVal = 40 sizeB.mockVal = 43.5 sizeC.mockVal = 42.0 expectedSizes = [sizeA, sizeB, sizeC] # When sut.sizes = expectedSizes # Then self.assertListEqual(expectedSizes, sut.sizes)
def generate_product(name=None): category = ProductCategory.JEDZENIE unit_price = random.randint(MIN_UNIT_PRICE, MAX_UNIT_PRICE) identifier = random.randint(MIN_IDENTIFIER, MAX_IDENTIFIER) if name is None: name = f"Product - {identifier}" return Product(name, category, unit_price, identifier)
def __init__(self, quantity, name, category, unit_price=None, identifier=None): if unit_price is None: unit_price = random.randint(1, 100) if identifier is None: identifier = random.randint(1, 100) self.quantity = quantity self.product = Product(name=name, category=category, unit_price=unit_price, identifier=identifier)
def test_getReleaseDate_shouldReturnDatetime(self): # Given sut = Product() givenTimezoneString = "US/Alaska" # See also: pytz.all_timezones timezone = pytz.timezone(givenTimezoneString) givenDatetime = dtt.datetime(2035, 7, 15, 9, 00, 00) # Leave datetime itself untouched, just add the timezone-data: expectedLocalDatetime = timezone.localize(givenDatetime) sut.setReleaseDate(givenDatetime, timezone=givenTimezoneString) # When result = sut.getReleaseDate(forTimezone=givenTimezoneString, forType=dtt.datetime) # Then self.assertEqual(expectedLocalDatetime, result)
def test_setReleaseDate_shouldSetCorrectDate(self): # Given sut = Product() berlinZone = pytz.timezone("Pacific/Fiji") # See also: pytz.all_timezones givenDatetime = dtt.datetime(2020, 4, 18, 16, 00, 00) # Leave datetime itself untouched, just add the timezone-data: berlinDatetime = berlinZone.localize(givenDatetime) # Convert to UTC time: utcDatetime: dtt.datetime = berlinDatetime.astimezone(pytz.utc) # Convert to UNIX epoch float: expectedUtcTimestamp = utcDatetime.timestamp() # 1587218400.0 # When sut.setReleaseDate(givenDatetime, timezone="Pacific/Fiji") self.assertEqual(expectedUtcTimestamp, sut.releaseDateStamp)
async def _setProductPrice(self, soup: BeautifulSoup, product: Product) -> ProductChanged: """ We need to find & extract price and currency from the following JS code: <script> fbq('track', 'ViewContent', { value: '64', currency: 'EUR', content_ids: '245134', content_type: 'product_group', }); </script> """ isProductChanged = False jsCodeToFind = "fbq\\(\'track\', \'AddToCart\'" reCompiled = re.compile(jsCodeToFind) try: javascriptStr = soup.find("script", attrs={ "type": "text/javascript" }, text=reCompiled).string priceStr = re.search(r"value:\s+(.*?)[,\n]", javascriptStr).group(1).strip("\'") priceFloat = float(priceStr) currency = re.search(r"currency:\s+(.*?)[,\n]", javascriptStr).group(1).strip("\'") except Exception as e: logger.warning("Failed finding product price or currency. %s. %s", e, product.url) self._failCount += 1 else: logger.debug("Extracted product price & currency from JS code. %s", product.url) if not product.basePrice or product.basePrice != priceFloat: product.basePrice = priceFloat product.currency = currency isProductChanged = True # note that we never switch back to False finally: return isProductChanged
def test_product_eq(): parameters = [("Ciastka", "Jedzenie", 4, "Ciastka", "Jedzenie", 4, True), ("Ciastka", "Jedzenie", 4, "Ciastka", "Jedzenie", 5, False), ("Ciastka", "Jedzenie", 4, "Ciastka", "Rozrywka", 4, False), ("Ciastka", "Jedzenie", 4, "Piwo", "Jedzenie", 4, False)] for params in parameters: name, category_name, price, other_name, other_category_name, other_price, expected_result = params result = Product(name, category_name, price) == Product(other_name, other_category_name, other_price) if result == expected_result: print("OK") else: print( f"Błąc! Dla danych {params} wynik: {result} powinien być: {expected_result}" )
def test_setReleaseDate_shouldLogOnError(self): # Given sut = Product() givenDatetime = dtt.datetime(2020, 1, 30, 15, 40, 00) invalidTimezone = "very/invalid" loggerName = "shop.product" loggerUnderTest = clog.getLogger(loggerName) expectedLogLevel = "ERROR" expectedPartOfLogMessage = "Could not set product release date" # When with self.assertLogs(loggerUnderTest, level=expectedLogLevel) as tlog: sut.setReleaseDate(givenDatetime, timezone=invalidTimezone) # Then self.assertEqual(1, len(tlog.output)) # expect one single log message in array self.assertIn(f"{expectedLogLevel}:{loggerName}:{expectedPartOfLogMessage}", tlog.output[0])