montana/Русский/Тесты/test_price_calculator.py

423 lines
19 KiB
Python
Raw Permalink Normal View History

#!/usr/bin/env python3
"""
test_price_calculator.py Unit tests для price_calculator.py
Montana Protocol
Тестирование ценового калькулятора и якоря Beeple
"""
import sys
import os
import unittest
from datetime import datetime, timezone
# Добавляем путь к модулю
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../экономика/банк_времени/код'))
from price_calculator import (
BeepleAnchor,
mta_to_usd,
usd_to_mta,
seconds_to_usd,
usd_to_seconds,
days_to_usd,
usd_to_days,
get_anchor_info,
format_price,
PizzaDayCalculator
)
class TestBeepleAnchorConstants(unittest.TestCase):
"""Тесты констант якоря Beeple"""
# ═══════════════════════════════════════════════════════════════════════
# BEEPLE ANCHOR CONSTANTS
# ═══════════════════════════════════════════════════════════════════════
def test_sale_price(self):
"""Цена продажи Beeple NFT"""
self.assertEqual(BeepleAnchor.SALE_PRICE_USD, 69_346_250.00)
def test_total_days(self):
"""Количество дней работы"""
self.assertEqual(BeepleAnchor.TOTAL_DAYS, 5000)
def test_sale_date(self):
"""Дата продажи"""
self.assertEqual(BeepleAnchor.SALE_DATE, "2021-03-11")
def test_usd_per_day(self):
"""USD за день работы"""
expected = BeepleAnchor.SALE_PRICE_USD / BeepleAnchor.TOTAL_DAYS
self.assertAlmostEqual(BeepleAnchor.USD_PER_DAY, expected, places=2)
self.assertAlmostEqual(BeepleAnchor.USD_PER_DAY, 13869.25, places=2)
def test_usd_per_hour(self):
"""USD за час работы"""
expected = BeepleAnchor.USD_PER_DAY / 24
self.assertAlmostEqual(BeepleAnchor.USD_PER_HOUR, expected, places=2)
self.assertAlmostEqual(BeepleAnchor.USD_PER_HOUR, 577.885, places=2)
def test_usd_per_minute(self):
"""USD за минуту работы"""
expected = BeepleAnchor.USD_PER_HOUR / 60
self.assertAlmostEqual(BeepleAnchor.USD_PER_MINUTE, expected, places=2)
self.assertAlmostEqual(BeepleAnchor.USD_PER_MINUTE, 9.6314, places=2)
def test_usd_per_second(self):
"""USD за секунду работы"""
expected = BeepleAnchor.USD_PER_MINUTE / 60
self.assertAlmostEqual(BeepleAnchor.USD_PER_SECOND, expected, places=4)
self.assertAlmostEqual(BeepleAnchor.USD_PER_SECOND, 0.1605, places=4)
def test_mta_per_second(self):
"""MTA за секунду"""
self.assertEqual(BeepleAnchor.MTA_PER_SECOND, 1.0)
def test_usd_per_mta(self):
"""USD за 1 MTA"""
self.assertEqual(BeepleAnchor.USD_PER_MTA, BeepleAnchor.USD_PER_SECOND)
class TestMTAtoUSD(unittest.TestCase):
"""Тесты конвертации MTA → USD"""
# ═══════════════════════════════════════════════════════════════════════
# MTA TO USD
# ═══════════════════════════════════════════════════════════════════════
def test_mta_to_usd_one_second(self):
"""1 MTA (1 секунда) → USD"""
result = mta_to_usd(1.0)
self.assertAlmostEqual(result, 0.1605, places=4)
def test_mta_to_usd_ten_minutes(self):
"""600 MTA (10 минут) → USD"""
result = mta_to_usd(600)
expected = 600 * BeepleAnchor.USD_PER_SECOND
self.assertAlmostEqual(result, expected, places=2)
self.assertAlmostEqual(result, 96.3, places=1)
def test_mta_to_usd_one_hour(self):
"""3600 MTA (1 час) → USD"""
result = mta_to_usd(3600)
expected = 3600 * BeepleAnchor.USD_PER_SECOND
self.assertAlmostEqual(result, expected, places=2)
self.assertAlmostEqual(result, 577.8, places=1)
def test_mta_to_usd_one_day(self):
"""86400 MTA (1 день) → USD"""
result = mta_to_usd(86400)
expected = 86400 * BeepleAnchor.USD_PER_SECOND
self.assertAlmostEqual(result, expected, places=2)
self.assertAlmostEqual(result, 13869.2, places=1)
def test_mta_to_usd_zero(self):
"""0 MTA → $0"""
result = mta_to_usd(0)
self.assertEqual(result, 0.0)
def test_mta_to_usd_large_number(self):
"""1,000,000 MTA → USD"""
result = mta_to_usd(1_000_000)
expected = 1_000_000 * BeepleAnchor.USD_PER_SECOND
self.assertAlmostEqual(result, expected, places=2)
class TestUSDtoMTA(unittest.TestCase):
"""Тесты конвертации USD → MTA"""
# ═══════════════════════════════════════════════════════════════════════
# USD TO MTA
# ═══════════════════════════════════════════════════════════════════════
def test_usd_to_mta_one_second_price(self):
"""$0.1605 → 1 MTA"""
result = usd_to_mta(0.1605)
self.assertAlmostEqual(result, 1.0, places=2)
def test_usd_to_mta_one_hundred(self):
"""$100 → MTA"""
result = usd_to_mta(100)
expected = 100 / BeepleAnchor.USD_PER_SECOND
self.assertAlmostEqual(result, expected, places=2)
self.assertAlmostEqual(result, 623.0, places=0)
def test_usd_to_mta_zero(self):
"""$0 → 0 MTA"""
result = usd_to_mta(0)
self.assertEqual(result, 0.0)
def test_usd_to_mta_roundtrip(self):
"""Roundtrip: MTA → USD → MTA"""
original = 1000.0
converted = mta_to_usd(original)
back = usd_to_mta(converted)
self.assertAlmostEqual(back, original, places=2)
class TestSecondsConversion(unittest.TestCase):
"""Тесты конвертации секунд"""
# ═══════════════════════════════════════════════════════════════════════
# SECONDS CONVERSION
# ═══════════════════════════════════════════════════════════════════════
def test_seconds_to_usd_one(self):
"""1 секунда → USD"""
result = seconds_to_usd(1)
self.assertAlmostEqual(result, 0.1605, places=4)
def test_seconds_to_usd_sixty(self):
"""60 секунд (1 минута) → USD"""
result = seconds_to_usd(60)
expected = 60 * BeepleAnchor.USD_PER_SECOND
self.assertAlmostEqual(result, expected, places=2)
def test_seconds_to_usd_ten_minutes(self):
"""600 секунд (10 минут) → USD"""
result = seconds_to_usd(600)
self.assertAlmostEqual(result, 96.3, places=1)
def test_usd_to_seconds_one_second_price(self):
"""$0.1605 → 1 секунда"""
result = usd_to_seconds(0.1605)
self.assertAlmostEqual(result, 1.0, places=2)
def test_usd_to_seconds_one_hundred(self):
"""$100 → секунды"""
result = usd_to_seconds(100)
expected = 100 / BeepleAnchor.USD_PER_SECOND
self.assertAlmostEqual(result, expected, places=2)
def test_seconds_roundtrip(self):
"""Roundtrip: секунды → USD → секунды"""
original = 3600 # 1 час
converted = seconds_to_usd(original)
back = usd_to_seconds(converted)
self.assertAlmostEqual(back, original, places=2)
class TestDaysConversion(unittest.TestCase):
"""Тесты конвертации дней"""
# ═══════════════════════════════════════════════════════════════════════
# DAYS CONVERSION
# ═══════════════════════════════════════════════════════════════════════
def test_days_to_usd_one(self):
"""1 день → USD"""
result = days_to_usd(1)
self.assertAlmostEqual(result, BeepleAnchor.USD_PER_DAY, places=2)
self.assertAlmostEqual(result, 13869.25, places=2)
def test_days_to_usd_5000(self):
"""5000 дней → USD (полная работа Beeple)"""
result = days_to_usd(5000)
self.assertAlmostEqual(result, BeepleAnchor.SALE_PRICE_USD, places=2)
def test_days_to_usd_fractional(self):
"""0.5 дня → USD"""
result = days_to_usd(0.5)
expected = BeepleAnchor.USD_PER_DAY * 0.5
self.assertAlmostEqual(result, expected, places=2)
def test_usd_to_days_one_day_price(self):
"""$13,869.25 → 1 день"""
result = usd_to_days(13869.25)
self.assertAlmostEqual(result, 1.0, places=2)
def test_usd_to_days_full_sale(self):
"""$69.3M → 5000 дней"""
result = usd_to_days(BeepleAnchor.SALE_PRICE_USD)
self.assertAlmostEqual(result, 5000, places=2)
def test_days_roundtrip(self):
"""Roundtrip: дни → USD → дни"""
original = 365 # 1 год
converted = days_to_usd(original)
back = usd_to_days(converted)
self.assertAlmostEqual(back, original, places=2)
class TestAnchorInfo(unittest.TestCase):
"""Тесты получения информации о якоре"""
# ═══════════════════════════════════════════════════════════════════════
# ANCHOR INFO
# ═══════════════════════════════════════════════════════════════════════
def test_get_anchor_info_structure(self):
"""Структура информации о якоре"""
info = get_anchor_info()
self.assertIsInstance(info, dict)
self.assertIn("sale_price_usd", info)
self.assertIn("total_days", info)
self.assertIn("sale_date", info)
self.assertIn("usd_per_second", info)
self.assertIn("usd_per_minute", info)
self.assertIn("usd_per_hour", info)
self.assertIn("usd_per_day", info)
self.assertIn("mta_per_second", info)
self.assertIn("usd_per_mta", info)
def test_get_anchor_info_values(self):
"""Значения в информации о якоре"""
info = get_anchor_info()
self.assertEqual(info["sale_price_usd"], 69_346_250.00)
self.assertEqual(info["total_days"], 5000)
self.assertEqual(info["sale_date"], "2021-03-11")
self.assertAlmostEqual(info["usd_per_second"], 0.1605, places=4)
self.assertEqual(info["mta_per_second"], 1.0)
class TestFormatPrice(unittest.TestCase):
"""Тесты форматирования цены"""
# ═══════════════════════════════════════════════════════════════════════
# FORMAT PRICE
# ═══════════════════════════════════════════════════════════════════════
def test_format_price_usd(self):
"""Форматирование в USD"""
result = format_price(96.31, "USD")
self.assertEqual(result, "$96.31 USD")
def test_format_price_mta(self):
"""Форматирование в MTA"""
usd_amount = 0.1605 # 1 MTA
result = format_price(usd_amount, "MTA")
self.assertIn("MTA", result)
self.assertIn("1.00", result)
def test_format_price_large_number(self):
"""Форматирование большого числа"""
result = format_price(13869.25, "USD")
self.assertEqual(result, "$13869.25 USD")
def test_format_price_zero(self):
"""Форматирование нуля"""
result = format_price(0.0, "USD")
self.assertEqual(result, "$0.00 USD")
class TestPizzaDayCalculator(unittest.TestCase):
"""Тесты Pizza Day механизма"""
# ═══════════════════════════════════════════════════════════════════════
# PIZZA DAY MECHANISM
# ═══════════════════════════════════════════════════════════════════════
def test_is_pizza_day_true(self):
"""22 мая — это Pizza Day"""
pizza_day = datetime(2025, 5, 22, tzinfo=timezone.utc)
result = PizzaDayCalculator.is_pizza_day(pizza_day)
self.assertTrue(result)
def test_is_pizza_day_false(self):
"""23 мая — НЕ Pizza Day"""
not_pizza_day = datetime(2025, 5, 23, tzinfo=timezone.utc)
result = PizzaDayCalculator.is_pizza_day(not_pizza_day)
self.assertFalse(result)
def test_is_pizza_day_different_year(self):
"""Pizza Day в другом году"""
pizza_day_2030 = datetime(2030, 5, 22, tzinfo=timezone.utc)
result = PizzaDayCalculator.is_pizza_day(pizza_day_2030)
self.assertTrue(result)
def test_days_until_pizza_day_before(self):
"""Дней до Pizza Day (до 22 мая)"""
date = datetime(2025, 5, 1, tzinfo=timezone.utc)
result = PizzaDayCalculator.days_until_pizza_day(date)
self.assertEqual(result, 21) # 22 - 1 = 21 день
def test_days_until_pizza_day_after(self):
"""Дней до Pizza Day (после 22 мая)"""
date = datetime(2025, 6, 1, tzinfo=timezone.utc)
result = PizzaDayCalculator.days_until_pizza_day(date)
# Должно быть ~355 дней до следующего 22 мая
self.assertGreater(result, 300)
self.assertLess(result, 366)
def test_days_until_pizza_day_on_pizza_day(self):
"""Дней до Pizza Day в сам Pizza Day"""
pizza_day = datetime(2025, 5, 22, tzinfo=timezone.utc)
result = PizzaDayCalculator.days_until_pizza_day(pizza_day)
# В сам Pizza Day — 0 дней до него (или 365 до следующего)
# Зависит от времени суток
self.assertIn(result, [0, 365])
def test_recalculate_anchor(self):
"""Пересчёт якоря с новыми значениями"""
new_price = 100_000_000 # $100M
new_days = 10_000
result = PizzaDayCalculator.recalculate_anchor(new_price, new_days)
self.assertEqual(result["sale_price_usd"], new_price)
self.assertEqual(result["total_days"], new_days)
self.assertAlmostEqual(result["usd_per_day"], 10_000, places=2)
self.assertAlmostEqual(result["usd_per_second"], 0.1157, places=4)
def test_recalculate_anchor_doubles_price(self):
"""Пересчёт с удвоенной ценой"""
original_price = BeepleAnchor.SALE_PRICE_USD
doubled_price = original_price * 2
result = PizzaDayCalculator.recalculate_anchor(doubled_price, BeepleAnchor.TOTAL_DAYS)
# USD/секунда должен удвоиться
expected_usd_per_sec = BeepleAnchor.USD_PER_SECOND * 2
self.assertAlmostEqual(result["usd_per_second"], expected_usd_per_sec, places=4)
class TestConsistency(unittest.TestCase):
"""Тесты консистентности расчётов"""
# ═══════════════════════════════════════════════════════════════════════
# CONSISTENCY
# ═══════════════════════════════════════════════════════════════════════
def test_seconds_equals_mta(self):
"""1 секунда = 1 MTA"""
seconds_value = seconds_to_usd(1)
mta_value = mta_to_usd(1)
self.assertAlmostEqual(seconds_value, mta_value, places=4)
def test_day_to_seconds_consistency(self):
"""86400 секунд = 1 день"""
usd_from_seconds = seconds_to_usd(86400)
usd_from_days = days_to_usd(1)
self.assertAlmostEqual(usd_from_seconds, usd_from_days, places=2)
def test_beeple_calculation_consistency(self):
"""$69.3M / 5000 дней / 86400 сек = $0.1605/сек"""
calculated = BeepleAnchor.SALE_PRICE_USD / BeepleAnchor.TOTAL_DAYS / 86400
self.assertAlmostEqual(calculated, BeepleAnchor.USD_PER_SECOND, places=4)
def test_all_units_consistent(self):
"""Все единицы согласованы"""
# 1 день = 24 часа = 1440 минут = 86400 секунд
day_price = BeepleAnchor.USD_PER_DAY
hour_price = BeepleAnchor.USD_PER_HOUR * 24
minute_price = BeepleAnchor.USD_PER_MINUTE * 1440
second_price = BeepleAnchor.USD_PER_SECOND * 86400
self.assertAlmostEqual(day_price, hour_price, places=2)
self.assertAlmostEqual(day_price, minute_price, places=2)
self.assertAlmostEqual(day_price, second_price, places=2)
# ═══════════════════════════════════════════════════════════════════════════
# RUN TESTS
# ═══════════════════════════════════════════════════════════════════════════
if __name__ == '__main__':
# Запускаем с verbose output
unittest.main(verbosity=2)