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

423 lines
19 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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)