39 lines
3.8 KiB
Python
39 lines
3.8 KiB
Python
import unittest,json,tempfile,hashlib
|
|
from pathlib import Path
|
|
from unittest.mock import patch
|
|
import numpy as np
|
|
import terrain_component_cleanup as m
|
|
class SingletonSelectorTests(unittest.TestCase):
|
|
def source(self):
|
|
a=np.full((32,32),225,np.uint8);a[:8,:]=154;a[8:16,:]=15;a[16:24,:]=82;a[24:,:16]=43;a[1,1]=245;a[1,2]=250;a[10,10]=102;return a
|
|
def palette(self):return np.stack([np.arange(256,dtype=np.uint8),np.arange(256,dtype=np.uint8)[::-1],np.arange(256,dtype=np.uint8)],-1)
|
|
def fields(self):
|
|
y,x=np.indices((512,512));return{i:np.stack([(x*19+y*11+i*7)%256,(x*13+y*17)%256,(x*3+y*7)%256],-1).astype(float)for i in range(5)}
|
|
def test_explicit_green_orange_red_and_protected(self):
|
|
self.assertEqual(m.singleton_material_labels(np.array([[102,69,70,73,75,82,38,40,41,43,245,250,255]],np.uint8)).tolist(),[[5,3,3,3,3,3,4,4,4,4,5,5,5]])
|
|
def test_unknown_classes_rejected(self):
|
|
for v in [32,34,37,44,65,68,71,72,74,76,101,103,147,160,181]:
|
|
with self.assertRaises(ValueError):m.singleton_material_labels(np.array([[v]],np.uint8))
|
|
def test_actual_original_support_and_isolated_fixture_contract(self):
|
|
d=Path(__file__).parent/'inputs'
|
|
for aid,count,rawfun in [('1054f',13,12),('10561',1,1)]:
|
|
a=m.decode_source32((d/(aid+'.pic')).read_bytes());m.singleton_material_labels(a);self.assertEqual(len(m.singleton_fidelity_union(a)),count);self.assertEqual(len(m.functional_support_union(a)),rawfun)
|
|
a=m.decode_source32((d/'1054f.pic').read_bytes());self.assertEqual(int(a[4,1]),102);self.assertIn([1,4],m.singleton_fidelity_union(a))
|
|
def test_green_and_fire_exact_with_positive_generated_fine_band(self):
|
|
a=self.source();p=self.palette();out,own,protected,stats=m.derive_singleton_tile(a,p,self.fields());guide=m.scale_nx(a,4);exact=np.repeat(np.repeat(p[guide],4,0),4,1);self.assertTrue(np.array_equal(out[protected],exact[protected]));self.assertEqual(stats['Original_functional_HD_credit'],0);self.assertGreater(stats['genuine_RGB_band_changed_nonfunctional_HDR_pixels'],0);self.assertEqual(stats['Source102_raw_original_retention_cells'],1);self.assertGreater(stats['Source_fidelity_owner_union_cells'],stats['functional_support_union_cells'])
|
|
def test_gray_donor_changes_only_gray_owners_not_earth_water_or_fire(self):
|
|
a=self.source();f=self.fields();p=self.palette();out,owners,protected,_=m.derive_singleton_tile(a,p,f);f[1]=255-f[1];changed,_,_,_=m.derive_singleton_tile(a,p,f);self.assertTrue(np.array_equal(out[owners!=1],changed[owners!=1]));self.assertTrue(np.any(out[owners==1]!=changed[owners==1]));self.assertTrue(np.array_equal(out[protected],changed[protected]))
|
|
def test_no_generated_band_is_original_only_rejected(self):
|
|
with self.assertRaisesRegex(ValueError,'Original-only'):m.derive_singleton_tile(self.source(),self.palette(),{i:np.full((512,512,3),90.,float)for i in range(5)})
|
|
def test_two_singletons_or_wrong_id_rejected_before_output(self):
|
|
for ids in [['1054f','10561'],['1054e']]:
|
|
with tempfile.TemporaryDirectory()as d:
|
|
d=Path(d);p=bytes(768);(d/'pal').write_bytes(p);rec={'method':m.METHOD,'operation':'first-singleton-tiles','palette':{'path':'pal','sha256':hashlib.sha256(p).hexdigest()},'sources':[{'asset':x}for x in ids]};(d/'recipe.json').write_text(json.dumps(rec))
|
|
with patch('sys.argv',['tool','--recipe',str(d/'recipe.json'),'--output',str(d/'none')]),self.assertRaisesRegex(ValueError,'selected singleton'):m.main()
|
|
self.assertFalse((d/'none').exists())
|
|
def test_source_red_gap_mask_is_exact_no_implicit_red_rectangle(self):
|
|
d=Path(__file__).parent/'inputs';a=m.decode_source32((d/'10561.pic').read_bytes());labels=m.singleton_material_labels(a);self.assertTrue(np.array_equal(labels==4,np.isin(a,[38,39,40,41,42,43])))
|
|
for x,y in [(25,0),(27,0),(30,0)]:self.assertNotEqual(int(labels[y,x]),4)
|
|
for x,y in [(27,6),(30,10)]:self.assertEqual(int(labels[y,x]),4)
|
|
if __name__=='__main__':unittest.main()
|