Merge owned systems into one addon while preserving resource identities. Gate player admission on the replicated prison scene, restore the original framed door, and hold enemy AI until escape. Correct scenario branding and author metadata, include publishing assets, and retain regression and native verification evidence.
79 lines
3.4 KiB
Python
79 lines
3.4 KiB
Python
"""Synthetic identity regression using actual Enforce inventory/count method bodies.
|
|
|
|
This checks source policy only; it does not simulate native inventory transfers.
|
|
"""
|
|
import unittest
|
|
from policy_harness import ROOT, body, run
|
|
|
|
|
|
def translated(source):
|
|
for old, new in [
|
|
('InventoryStorageManagerComponent inventory', 'InventoryStorageManagerComponent* inventory'),
|
|
('notnull array<IEntity> items', 'Array<Entity*>& items'),
|
|
('out array<IEntity> items', 'Array<Entity*>& items'),
|
|
('array<IEntity>', 'Array<Entity*>'),
|
|
('IEntity item', 'Entity* item'),
|
|
('foreach (', 'for ('),
|
|
('inventory.GetItems', 'inventory->GetItems'),
|
|
('item.GetPrefabData()', 'item->GetPrefabData()'),
|
|
('.GetPrefabName()', '->GetPrefabName()'),
|
|
('ERR_Inventory.', 'ERR_Inventory::'),
|
|
('int count;', 'int count = 0;'),
|
|
]:
|
|
source = source.replace(old, new)
|
|
return source
|
|
|
|
|
|
class InventoryEnumerationPolicy(unittest.TestCase):
|
|
def test_duplicate_references_distinct_rounds_and_cross_inventory_union(self):
|
|
helper = ROOT / 'addons/core/Scripts/Game/ERR/00_Core/ERR_Inventory.c'
|
|
mortar = ROOT / 'addons/core/Scripts/Game/ERR/10_AI/ERR_MortarBattery.c'
|
|
methods = '\n'.join(translated(body(helper, signature)) for signature in (
|
|
'static int AppendUnique(', 'static int Items('))
|
|
count = translated(body(mortar, 'int InventoryShells('))
|
|
run(r'''
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <string>
|
|
#include <vector>
|
|
template <typename T> struct Array : std::vector<T> {
|
|
using std::vector<T>::vector;
|
|
bool Contains(T v) const { return std::find(this->begin(),this->end(),v)!=this->end(); }
|
|
void Insert(T v) { this->push_back(v); }
|
|
void Clear() { this->clear(); }
|
|
int Count() const { return this->size(); }
|
|
};
|
|
struct Prefab { std::string name; std::string GetPrefabName() { return name; } };
|
|
struct Entity { Prefab* prefab; Prefab* GetPrefabData() { return prefab; } };
|
|
struct InventoryStorageManagerComponent {
|
|
Array<Entity*> raw;
|
|
void GetItems(Array<Entity*>& out) { out = raw; }
|
|
};
|
|
const std::string SHELL = "mortar-shell";
|
|
struct ERR_Inventory {
|
|
''' + methods + '\n};\n' + count + r'''
|
|
int main() {
|
|
Prefab shell{SHELL}, watch{"watch"};
|
|
Entity roundA{&shell}, roundB{&shell}, watchA{&watch}, missingPrefab{nullptr};
|
|
InventoryStorageManagerComponent one{{&roundA,&roundA,nullptr,&roundB,&watchA,&watchA,&missingPrefab}};
|
|
Array<Entity*> unique{&watchA};
|
|
assert(ERR_Inventory::Items(&one,unique)==4);
|
|
assert(unique[0]==&roundA && unique[1]==&roundB && unique[2]==&watchA && unique[3]==&missingPrefab);
|
|
assert(InventoryShells(&one)==2); // Different shells share one prefab, not one identity.
|
|
assert(one.raw.size()==7 && one.raw[0]==one.raw[1]); // Enumeration remains untouched.
|
|
InventoryStorageManagerComponent two{{&roundB,&roundB,&roundA}};
|
|
assert(ERR_Inventory::AppendUnique(&two,unique)==4); // Cross-inventory repeated identities.
|
|
assert(ERR_Inventory::AppendUnique(nullptr,unique)==4);
|
|
assert(ERR_Inventory::Items(nullptr,unique)==0 && unique.empty());
|
|
assert(InventoryShells(nullptr)==0);
|
|
InventoryStorageManagerComponent repeated{{&roundA,&roundA,&roundA}};
|
|
assert(InventoryShells(&repeated)==1);
|
|
InventoryStorageManagerComponent empty{{nullptr,&missingPrefab,&watchA}};
|
|
assert(InventoryShells(&empty)==0);
|
|
}
|
|
''')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|