160 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			160 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| 
								 | 
							
								import unittest
							 | 
						||
| 
								 | 
							
								from collections import Counter
							 | 
						||
| 
								 | 
							
								from typing import ClassVar, Set
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								from . import SVTestBase
							 | 
						||
| 
								 | 
							
								from ..content.feature import friendsanity
							 | 
						||
| 
								 | 
							
								from ..options import Friendsanity, FriendsanityHeartSize
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								all_vanilla_bachelor = {
							 | 
						||
| 
								 | 
							
								    "Harvey", "Elliott", "Sam", "Alex", "Shane", "Sebastian", "Emily", "Haley", "Leah", "Abigail", "Penny", "Maru"
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								all_vanilla_starting_npc = {
							 | 
						||
| 
								 | 
							
								    "Alex", "Elliott", "Harvey", "Sam", "Sebastian", "Shane", "Abigail", "Emily", "Haley", "Leah", "Maru", "Penny", "Caroline", "Clint", "Demetrius", "Evelyn",
							 | 
						||
| 
								 | 
							
								    "George", "Gus", "Jas", "Jodi", "Lewis", "Linus", "Marnie", "Pam", "Pierre", "Robin", "Vincent", "Willy", "Wizard", "Pet",
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								all_vanilla_npc = {
							 | 
						||
| 
								 | 
							
								    "Alex", "Elliott", "Harvey", "Sam", "Sebastian", "Shane", "Abigail", "Emily", "Haley", "Leah", "Maru", "Penny", "Caroline", "Clint", "Demetrius", "Evelyn",
							 | 
						||
| 
								 | 
							
								    "George", "Gus", "Jas", "Jodi", "Lewis", "Linus", "Marnie", "Pam", "Pierre", "Robin", "Vincent", "Willy", "Wizard", "Pet", "Sandy", "Dwarf", "Kent", "Leo",
							 | 
						||
| 
								 | 
							
								    "Krobus"
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class SVFriendsanityTestBase(SVTestBase):
							 | 
						||
| 
								 | 
							
								    expected_npcs: ClassVar[Set[str]] = set()
							 | 
						||
| 
								 | 
							
								    expected_pet_heart_size: ClassVar[Set[str]] = set()
							 | 
						||
| 
								 | 
							
								    expected_bachelor_heart_size: ClassVar[Set[str]] = set()
							 | 
						||
| 
								 | 
							
								    expected_other_heart_size: ClassVar[Set[str]] = set()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @classmethod
							 | 
						||
| 
								 | 
							
								    def setUpClass(cls) -> None:
							 | 
						||
| 
								 | 
							
								        if cls is SVFriendsanityTestBase:
							 | 
						||
| 
								 | 
							
								            raise unittest.SkipTest("Base tests disabled")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        super().setUpClass()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def test_friendsanity(self):
							 | 
						||
| 
								 | 
							
								        with self.subTest("Items are valid"):
							 | 
						||
| 
								 | 
							
								            self.check_all_items_match_expected_npcs()
							 | 
						||
| 
								 | 
							
								        with self.subTest("Correct number of items"):
							 | 
						||
| 
								 | 
							
								            self.check_correct_number_of_items()
							 | 
						||
| 
								 | 
							
								        with self.subTest("Locations are valid"):
							 | 
						||
| 
								 | 
							
								            self.check_all_locations_match_expected_npcs()
							 | 
						||
| 
								 | 
							
								        with self.subTest("Locations heart size are valid"):
							 | 
						||
| 
								 | 
							
								            self.check_all_locations_match_heart_size()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def check_all_items_match_expected_npcs(self):
							 | 
						||
| 
								 | 
							
								        npc_names = {
							 | 
						||
| 
								 | 
							
								            name
							 | 
						||
| 
								 | 
							
								            for item in self.multiworld.itempool
							 | 
						||
| 
								 | 
							
								            if (name := friendsanity.extract_npc_from_item_name(item.name)) is not None
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        self.assertEqual(npc_names, self.expected_npcs)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def check_correct_number_of_items(self):
							 | 
						||
| 
								 | 
							
								        item_by_npc = Counter()
							 | 
						||
| 
								 | 
							
								        for item in self.multiworld.itempool:
							 | 
						||
| 
								 | 
							
								            name = friendsanity.extract_npc_from_item_name(item.name)
							 | 
						||
| 
								 | 
							
								            if name is None:
							 | 
						||
| 
								 | 
							
								                continue
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            item_by_npc[name] += 1
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        for name, count in item_by_npc.items():
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if name == "Pet":
							 | 
						||
| 
								 | 
							
								                self.assertEqual(count, len(self.expected_pet_heart_size))
							 | 
						||
| 
								 | 
							
								            elif self.world.content.villagers[name].bachelor:
							 | 
						||
| 
								 | 
							
								                self.assertEqual(count, len(self.expected_bachelor_heart_size))
							 | 
						||
| 
								 | 
							
								            else:
							 | 
						||
| 
								 | 
							
								                self.assertEqual(count, len(self.expected_other_heart_size))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def check_all_locations_match_expected_npcs(self):
							 | 
						||
| 
								 | 
							
								        npc_names = {
							 | 
						||
| 
								 | 
							
								            name_and_heart[0]
							 | 
						||
| 
								 | 
							
								            for location_name in self.get_real_location_names()
							 | 
						||
| 
								 | 
							
								            if (name_and_heart := friendsanity.extract_npc_from_location_name(location_name))[0] is not None
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        self.assertEqual(npc_names, self.expected_npcs)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def check_all_locations_match_heart_size(self):
							 | 
						||
| 
								 | 
							
								        for location_name in self.get_real_location_names():
							 | 
						||
| 
								 | 
							
								            name, heart_size = friendsanity.extract_npc_from_location_name(location_name)
							 | 
						||
| 
								 | 
							
								            if name is None:
							 | 
						||
| 
								 | 
							
								                continue
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if name == "Pet":
							 | 
						||
| 
								 | 
							
								                self.assertIn(heart_size, self.expected_pet_heart_size)
							 | 
						||
| 
								 | 
							
								            elif self.world.content.villagers[name].bachelor:
							 | 
						||
| 
								 | 
							
								                self.assertIn(heart_size, self.expected_bachelor_heart_size)
							 | 
						||
| 
								 | 
							
								            else:
							 | 
						||
| 
								 | 
							
								                self.assertIn(heart_size, self.expected_other_heart_size)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class TestFriendsanityNone(SVFriendsanityTestBase):
							 | 
						||
| 
								 | 
							
								    options = {
							 | 
						||
| 
								 | 
							
								        Friendsanity: Friendsanity.option_none,
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @property
							 | 
						||
| 
								 | 
							
								    def run_default_tests(self) -> bool:
							 | 
						||
| 
								 | 
							
								        # None is default
							 | 
						||
| 
								 | 
							
								        return False
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class TestFriendsanityBachelors(SVFriendsanityTestBase):
							 | 
						||
| 
								 | 
							
								    options = {
							 | 
						||
| 
								 | 
							
								        Friendsanity: Friendsanity.option_bachelors,
							 | 
						||
| 
								 | 
							
								        FriendsanityHeartSize: 1,
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    expected_npcs = all_vanilla_bachelor
							 | 
						||
| 
								 | 
							
								    expected_bachelor_heart_size = {1, 2, 3, 4, 5, 6, 7, 8}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class TestFriendsanityStartingNpcs(SVFriendsanityTestBase):
							 | 
						||
| 
								 | 
							
								    options = {
							 | 
						||
| 
								 | 
							
								        Friendsanity: Friendsanity.option_starting_npcs,
							 | 
						||
| 
								 | 
							
								        FriendsanityHeartSize: 1,
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    expected_npcs = all_vanilla_starting_npc
							 | 
						||
| 
								 | 
							
								    expected_pet_heart_size = {1, 2, 3, 4, 5}
							 | 
						||
| 
								 | 
							
								    expected_bachelor_heart_size = {1, 2, 3, 4, 5, 6, 7, 8}
							 | 
						||
| 
								 | 
							
								    expected_other_heart_size = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class TestFriendsanityAllNpcs(SVFriendsanityTestBase):
							 | 
						||
| 
								 | 
							
								    options = {
							 | 
						||
| 
								 | 
							
								        Friendsanity: Friendsanity.option_all,
							 | 
						||
| 
								 | 
							
								        FriendsanityHeartSize: 4,
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    expected_npcs = all_vanilla_npc
							 | 
						||
| 
								 | 
							
								    expected_pet_heart_size = {4, 5}
							 | 
						||
| 
								 | 
							
								    expected_bachelor_heart_size = {4, 8}
							 | 
						||
| 
								 | 
							
								    expected_other_heart_size = {4, 8, 10}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class TestFriendsanityHeartSize3(SVFriendsanityTestBase):
							 | 
						||
| 
								 | 
							
								    options = {
							 | 
						||
| 
								 | 
							
								        Friendsanity: Friendsanity.option_all_with_marriage,
							 | 
						||
| 
								 | 
							
								        FriendsanityHeartSize: 3,
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    expected_npcs = all_vanilla_npc
							 | 
						||
| 
								 | 
							
								    expected_pet_heart_size = {3, 5}
							 | 
						||
| 
								 | 
							
								    expected_bachelor_heart_size = {3, 6, 9, 12, 14}
							 | 
						||
| 
								 | 
							
								    expected_other_heart_size = {3, 6, 9, 10}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class TestFriendsanityHeartSize5(SVFriendsanityTestBase):
							 | 
						||
| 
								 | 
							
								    options = {
							 | 
						||
| 
								 | 
							
								        Friendsanity: Friendsanity.option_all_with_marriage,
							 | 
						||
| 
								 | 
							
								        FriendsanityHeartSize: 5,
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    expected_npcs = all_vanilla_npc
							 | 
						||
| 
								 | 
							
								    expected_pet_heart_size = {5}
							 | 
						||
| 
								 | 
							
								    expected_bachelor_heart_size = {5, 10, 14}
							 | 
						||
| 
								 | 
							
								    expected_other_heart_size = {5, 10}
							 |