test_stl_thumbnail.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. """Unit tests for the STL thumbnail service."""
  2. import tempfile
  3. from pathlib import Path
  4. from unittest.mock import MagicMock, patch
  5. import pytest
  6. def _check_trimesh_available():
  7. """Check if trimesh is available for import."""
  8. try:
  9. import trimesh
  10. return True
  11. except ImportError:
  12. return False
  13. class TestStlThumbnailService:
  14. """Tests for STL thumbnail generation service."""
  15. def test_generate_stl_thumbnail_imports_available(self):
  16. """Test that required imports are available."""
  17. try:
  18. import matplotlib
  19. import trimesh
  20. assert trimesh is not None
  21. assert matplotlib is not None
  22. except ImportError as e:
  23. pytest.skip(f"Required dependencies not installed: {e}")
  24. def test_generate_stl_thumbnail_returns_none_on_missing_deps(self):
  25. """Test graceful degradation when dependencies are missing."""
  26. from backend.app.services.stl_thumbnail import generate_stl_thumbnail
  27. with tempfile.TemporaryDirectory() as tmpdir:
  28. stl_path = Path(tmpdir) / "test.stl"
  29. thumbnails_dir = Path(tmpdir)
  30. # Create a dummy STL file (will fail to parse)
  31. stl_path.write_text("invalid stl content")
  32. # Should return None on failure, not raise
  33. result = generate_stl_thumbnail(stl_path, thumbnails_dir)
  34. assert result is None
  35. @pytest.mark.skipif(
  36. not _check_trimesh_available(),
  37. reason="trimesh not installed",
  38. )
  39. def test_generate_stl_thumbnail_with_simple_cube(self):
  40. """Test thumbnail generation with a simple cube STL."""
  41. from backend.app.services.stl_thumbnail import generate_stl_thumbnail
  42. with tempfile.TemporaryDirectory() as tmpdir:
  43. stl_path = Path(tmpdir) / "cube.stl"
  44. thumbnails_dir = Path(tmpdir)
  45. # Create a simple ASCII STL cube
  46. stl_content = """solid cube
  47. facet normal 0 0 -1
  48. outer loop
  49. vertex 0 0 0
  50. vertex 1 0 0
  51. vertex 1 1 0
  52. endloop
  53. endfacet
  54. facet normal 0 0 -1
  55. outer loop
  56. vertex 0 0 0
  57. vertex 1 1 0
  58. vertex 0 1 0
  59. endloop
  60. endfacet
  61. facet normal 0 0 1
  62. outer loop
  63. vertex 0 0 1
  64. vertex 1 1 1
  65. vertex 1 0 1
  66. endloop
  67. endfacet
  68. facet normal 0 0 1
  69. outer loop
  70. vertex 0 0 1
  71. vertex 0 1 1
  72. vertex 1 1 1
  73. endloop
  74. endfacet
  75. facet normal 0 -1 0
  76. outer loop
  77. vertex 0 0 0
  78. vertex 1 0 1
  79. vertex 1 0 0
  80. endloop
  81. endfacet
  82. facet normal 0 -1 0
  83. outer loop
  84. vertex 0 0 0
  85. vertex 0 0 1
  86. vertex 1 0 1
  87. endloop
  88. endfacet
  89. facet normal 1 0 0
  90. outer loop
  91. vertex 1 0 0
  92. vertex 1 0 1
  93. vertex 1 1 1
  94. endloop
  95. endfacet
  96. facet normal 1 0 0
  97. outer loop
  98. vertex 1 0 0
  99. vertex 1 1 1
  100. vertex 1 1 0
  101. endloop
  102. endfacet
  103. facet normal 0 1 0
  104. outer loop
  105. vertex 0 1 0
  106. vertex 1 1 0
  107. vertex 1 1 1
  108. endloop
  109. endfacet
  110. facet normal 0 1 0
  111. outer loop
  112. vertex 0 1 0
  113. vertex 1 1 1
  114. vertex 0 1 1
  115. endloop
  116. endfacet
  117. facet normal -1 0 0
  118. outer loop
  119. vertex 0 0 0
  120. vertex 0 1 0
  121. vertex 0 1 1
  122. endloop
  123. endfacet
  124. facet normal -1 0 0
  125. outer loop
  126. vertex 0 0 0
  127. vertex 0 1 1
  128. vertex 0 0 1
  129. endloop
  130. endfacet
  131. endsolid cube"""
  132. stl_path.write_text(stl_content)
  133. result = generate_stl_thumbnail(stl_path, thumbnails_dir)
  134. # Should return a path to the generated thumbnail
  135. if result:
  136. assert Path(result).exists()
  137. assert Path(result).suffix == ".png"
  138. # If result is None, dependencies might not be fully functional
  139. # which is acceptable
  140. def test_generate_stl_thumbnail_nonexistent_file(self):
  141. """Test thumbnail generation with nonexistent file."""
  142. from backend.app.services.stl_thumbnail import generate_stl_thumbnail
  143. with tempfile.TemporaryDirectory() as tmpdir:
  144. stl_path = Path(tmpdir) / "nonexistent.stl"
  145. thumbnails_dir = Path(tmpdir)
  146. result = generate_stl_thumbnail(stl_path, thumbnails_dir)
  147. assert result is None
  148. def test_generate_stl_thumbnail_empty_file(self):
  149. """Test thumbnail generation with empty file."""
  150. from backend.app.services.stl_thumbnail import generate_stl_thumbnail
  151. with tempfile.TemporaryDirectory() as tmpdir:
  152. stl_path = Path(tmpdir) / "empty.stl"
  153. thumbnails_dir = Path(tmpdir)
  154. # Create empty file
  155. stl_path.write_bytes(b"")
  156. result = generate_stl_thumbnail(stl_path, thumbnails_dir)
  157. assert result is None
  158. class TestStlThumbnailConstants:
  159. """Tests for STL thumbnail service constants."""
  160. def test_bambu_green_color(self):
  161. """Test that Bambu green color is defined."""
  162. from backend.app.services.stl_thumbnail import BAMBU_GREEN
  163. assert BAMBU_GREEN == "#00AE42"
  164. def test_background_color(self):
  165. """Test that background color is defined."""
  166. from backend.app.services.stl_thumbnail import BACKGROUND_COLOR
  167. assert BACKGROUND_COLOR == "#1a1a1a"
  168. def test_max_vertices_threshold(self):
  169. """Test that max vertices threshold is defined."""
  170. from backend.app.services.stl_thumbnail import MAX_VERTICES
  171. assert MAX_VERTICES == 100000