forked from expo/troggle
187 lines
7.6 KiB
Python
187 lines
7.6 KiB
Python
import os
|
|
import pathlib
|
|
import tempfile
|
|
|
|
from django.test import TestCase
|
|
|
|
import settings
|
|
from troggle.parsers import drawings
|
|
from troggle.core.models.survex import DrawingFile
|
|
from troggle.core.models.wallets import Wallet
|
|
from troggle.core.models.survex import SingleScan
|
|
from troggle.core.models.troggle import DataIssue
|
|
|
|
|
|
class DrawingsPathlibTests(TestCase):
|
|
def test_load_drawings_creates_expected_entries(self):
|
|
with tempfile.TemporaryDirectory() as td:
|
|
# create a small tree
|
|
p = pathlib.Path(td)
|
|
(p / 'one.pdf').write_text('pdf')
|
|
(p / 'two.txt').write_text('txt')
|
|
sub = p / 'dir'
|
|
sub.mkdir()
|
|
(sub / 'three.png').write_text('png')
|
|
sub2 = p / 'dir2'
|
|
sub2.mkdir()
|
|
(sub2 / 'abc.th2').write_text('th2')
|
|
(sub2 / 'abc.th').write_text('th')
|
|
|
|
# point the module at our tempdir
|
|
settings.DRAWINGS_DATA = td
|
|
|
|
drawings.load_drawings_files()
|
|
|
|
# all files should be present
|
|
self.assertTrue(DrawingFile.objects.filter(dwgpath='one.pdf').exists())
|
|
self.assertTrue(DrawingFile.objects.filter(dwgpath='two.txt').exists())
|
|
self.assertTrue(DrawingFile.objects.filter(dwgpath='dir/three.png').exists())
|
|
self.assertTrue(DrawingFile.objects.filter(dwgpath='dir2/abc.th2').exists())
|
|
self.assertTrue(DrawingFile.objects.filter(dwgpath='dir2/abc.th').exists())
|
|
|
|
def test_hidden_and_backup_skipped(self):
|
|
with tempfile.TemporaryDirectory() as td:
|
|
p = pathlib.Path(td)
|
|
(p / '.hidden').write_text('hid')
|
|
(p / 'file~').write_text('bak')
|
|
settings.DRAWINGS_DATA = td
|
|
|
|
drawings.load_drawings_files()
|
|
|
|
# Should not import hidden or backup files
|
|
self.assertFalse(DrawingFile.objects.filter(dwgpath='.hidden').exists())
|
|
self.assertFalse(DrawingFile.objects.filter(dwgpath='file~').exists())
|
|
|
|
def test_no_extension_file(self):
|
|
with tempfile.TemporaryDirectory() as td:
|
|
p = pathlib.Path(td)
|
|
(p / 'noext').write_text('data')
|
|
settings.DRAWINGS_DATA = td
|
|
|
|
drawings.load_drawings_files()
|
|
|
|
self.assertTrue(DrawingFile.objects.filter(dwgpath='noext').exists())
|
|
|
|
def test_git_dir_skipped(self):
|
|
with tempfile.TemporaryDirectory() as td:
|
|
p = pathlib.Path(td)
|
|
g = p / '.git'
|
|
g.mkdir()
|
|
(g / 'secret.txt').write_text('top secret')
|
|
settings.DRAWINGS_DATA = td
|
|
|
|
drawings.load_drawings_files()
|
|
|
|
self.assertFalse(DrawingFile.objects.filter(dwgpath='.git/secret.txt').exists())
|
|
|
|
def test_bulk_create_chunks(self):
|
|
# Create more than chunk size files to ensure bulk_create is called in multiple chunks
|
|
count = 800
|
|
with tempfile.TemporaryDirectory() as td:
|
|
p = pathlib.Path(td)
|
|
for i in range(count):
|
|
(p / f'file{i}.txt').write_text('x')
|
|
settings.DRAWINGS_DATA = td
|
|
|
|
drawings.load_drawings_files()
|
|
|
|
self.assertEqual(DrawingFile.objects.count(), count)
|
|
|
|
def test_parse_tunnel_links_wallet_and_scan(self):
|
|
# Create a wallet and a singlescan, then ensure parse_tnl_file links them
|
|
w = Wallet.objects.create(fpath='x', walletname='2025#20')
|
|
ss = SingleScan.objects.create(ffile='x', name='notes.jpg', wallet=w)
|
|
df = DrawingFile.objects.create(dwgpath='tst.th', dwgname='tst')
|
|
|
|
drawings.parse_tnl_file(df, '2025#20/notes.jpg')
|
|
|
|
self.assertIn(w, df.dwgwallets.all())
|
|
self.assertIn(ss, df.scans.all())
|
|
|
|
def test_drawing_reference_multiple_creates_dataissue(self):
|
|
df1 = DrawingFile.objects.create(dwgpath='ref1', dwgname='shared')
|
|
df2 = DrawingFile.objects.create(dwgpath='ref2', dwgname='shared')
|
|
dfmain = DrawingFile.objects.create(dwgpath='main', dwgname='main')
|
|
|
|
drawings.parse_tnl_file(dfmain, 'shared')
|
|
|
|
di = DataIssue.objects.filter(parser='Tunnel', message__contains="files named 'shared'")
|
|
self.assertTrue(di.exists())
|
|
|
|
def test_drawing_reference_single_no_dataissue(self):
|
|
DrawingFile.objects.create(dwgpath='ref3', dwgname='unique')
|
|
dfmain = DrawingFile.objects.create(dwgpath='main2', dwgname='main2')
|
|
|
|
drawings.parse_tnl_file(dfmain, 'unique')
|
|
|
|
di = DataIssue.objects.filter(parser='Tunnel', message__contains="files named 'unique'")
|
|
self.assertFalse(di.exists())
|
|
|
|
def test_extension_helpers_and_constants(self):
|
|
# Helpers should recognise supported/image suffixes (case-insensitive)
|
|
self.assertTrue(drawings._is_supported_suffix('.png'))
|
|
self.assertTrue(drawings._is_supported_suffix('.xml'))
|
|
self.assertTrue(drawings._is_supported_suffix('.TH'))
|
|
self.assertFalse(drawings._is_supported_suffix(''))
|
|
self.assertFalse(drawings._is_supported_suffix('.exe'))
|
|
|
|
self.assertTrue(drawings._is_image_suffix('.png'))
|
|
self.assertTrue(drawings._is_image_suffix('.JPEG'))
|
|
self.assertFalse(drawings._is_image_suffix('.xml'))
|
|
self.assertFalse(drawings._is_image_suffix(''))
|
|
|
|
# Constants should include expected values and be consistent
|
|
self.assertIn('.png', drawings.IMAGE_EXTS)
|
|
self.assertEqual(set(drawings.IMAGE_LIKE_EXTS), set(drawings.IMAGE_EXTS))
|
|
self.assertIn('.th', drawings.SUPPORTED_EXTENSIONS)
|
|
self.assertIn('.png', drawings.SUPPORTED_EXTENSIONS)
|
|
|
|
def test_fetch_drawingfiles_by_paths_chunks(self):
|
|
# Create more items than typical SQLite parameter limit to ensure chunking
|
|
count = 1200
|
|
rel_paths = []
|
|
objs = []
|
|
for i in range(count):
|
|
rel = f'bigdir/file{i}.txt'
|
|
rel_paths.append(rel)
|
|
objs.append(DrawingFile(dwgpath=rel, dwgname=f'name{i}'))
|
|
|
|
# Bulk create them efficiently
|
|
DrawingFile.objects.bulk_create(objs)
|
|
|
|
mapping = drawings.fetch_drawingfiles_by_paths(rel_paths, chunk_size=500)
|
|
self.assertEqual(len(mapping), count)
|
|
# Spot-check a few entries
|
|
self.assertIn('bigdir/file0.txt', mapping)
|
|
self.assertIn(f'bigdir/file{count-1}.txt', mapping)
|
|
|
|
def test_assign_wallets_for_model_assigns_and_returns_wallets(self):
|
|
w = Wallet.objects.create(fpath='x', walletname='2025#20')
|
|
df = DrawingFile.objects.create(dwgpath='assign.th', dwgname='assign')
|
|
|
|
res = drawings._assign_wallets_for_model(df, '2025#20', parser_label='AssignTest')
|
|
|
|
self.assertTrue(res)
|
|
self.assertIn(w, df.dwgwallets.all())
|
|
|
|
def test_assign_wallets_for_model_creates_dataissue_on_missing(self):
|
|
df = DrawingFile.objects.create(dwgpath='missing.th', dwgname='missing')
|
|
|
|
drawings._assign_wallets_for_model(df, 'NONEXISTENT', parser_label='AssignMissing')
|
|
|
|
di = DataIssue.objects.filter(parser='AssignMissing', message__contains='not found')
|
|
self.assertTrue(di.exists())
|
|
|
|
def test_assign_wallets_for_model_records_dataissue_on_exception(self):
|
|
# Patch Wallet.objects.filter to raise an exception
|
|
from unittest.mock import patch
|
|
|
|
df = DrawingFile.objects.create(dwgpath='err.th', dwgname='err')
|
|
|
|
with patch('troggle.core.models.wallets.Wallet.objects.filter') as mock_filter:
|
|
mock_filter.side_effect = RuntimeError('boom')
|
|
drawings._assign_wallets_for_model(df, 'WHATEVER', parser_label='AssignError')
|
|
|
|
di = DataIssue.objects.filter(parser='AssignError', message__contains='Exception')
|
|
self.assertTrue(di.exists())
|