Warning, /firebird/firebird-ng/src/app/utils/three.utils.spec.ts is written in an unsupported language. File is not indexed.
0001 import {walkObject3DNodes, NodeWalkCallback, findObject3DNodes} from './three.utils';
0002 import * as THREE from 'three';
0003 import { isColorable, getColorOrDefault } from './three.utils';
0004
0005 describe('walkObject3dNodes', () => {
0006 let root: THREE.Object3D;
0007 let callback: jasmine.Spy<NodeWalkCallback>;
0008
0009 beforeEach(() => {
0010 // Create a simple scene graph: root -> child -> grandchild
0011 root = new THREE.Object3D();
0012 root.name = 'root';
0013
0014 const child = new THREE.Object3D();
0015 child.name = 'child';
0016 root.add(child);
0017
0018 const grandchild = new THREE.Object3D();
0019 grandchild.name = 'grandchild';
0020 child.add(grandchild);
0021
0022 // Setup callback spy
0023 callback = jasmine.createSpy('callback');
0024 });
0025
0026 it('should invoke callback for each node when no pattern is given', () => {
0027 walkObject3DNodes(root, callback);
0028 expect(callback.calls.count()).toBe(3);
0029 expect(callback.calls.argsFor(0)).toEqual([root, 'root', 0]);
0030 expect(callback.calls.argsFor(1)).toEqual([root.children[0], 'root/child', 1]);
0031 expect(callback.calls.argsFor(2)).toEqual([root.children[0].children[0], 'root/child/grandchild', 2]);
0032 });
0033
0034 it('should respect the maxLevel parameter', () => {
0035 walkObject3DNodes(root, callback, {maxLevel:1});
0036 expect(callback.calls.count()).toBe(2);
0037 });
0038
0039 it('should correctly match nodes when a pattern is given', () => {
0040 const pattern = 'root/child';
0041 walkObject3DNodes(root, callback, {pattern: pattern});
0042 expect(callback).toHaveBeenCalledWith(jasmine.objectContaining({ name: 'child' }), 'root/child', 1);
0043 });
0044
0045 it('should return the correct number of processed nodes', () => {
0046 const processed = walkObject3DNodes(root, callback);
0047 expect(processed).toBe(3); // Including root, child, grandchild
0048 });
0049
0050 it('should not invoke callback for non-matching pattern', () => {
0051 const pattern = 'nonexistent';
0052 walkObject3DNodes(root, callback, {pattern: pattern});
0053 expect(callback).not.toHaveBeenCalled();
0054 });
0055 });
0056
0057
0058 describe('Material color functions', () => {
0059 describe('isColorable', () => {
0060 it('should return true if material has a color property', () => {
0061 const colorableMaterial = { color: new THREE.Color(255, 0, 0) };
0062 expect(isColorable(colorableMaterial)).toBeTrue();
0063 });
0064
0065 it('should return false if material does not have a color property', () => {
0066 const nonColorableMaterial = { noColor: true };
0067 expect(isColorable(nonColorableMaterial)).toBeFalse();
0068 });
0069 });
0070
0071 describe('getColorOrDefault', () => {
0072 it('should return the material color if material is colorable', () => {
0073 const colorableMaterial = { color: new THREE.Color(255, 0, 0) };
0074 const defaultColor = new THREE.Color(0, 0, 0);
0075 expect(getColorOrDefault(colorableMaterial, defaultColor)).toEqual(colorableMaterial.color);
0076 });
0077
0078 it('should return the default color if material is not colorable', () => {
0079 const nonColorableMaterial = { noColor: true };
0080 const defaultColor = new THREE.Color(0, 0, 0);
0081 expect(getColorOrDefault(nonColorableMaterial, defaultColor)).toEqual(defaultColor);
0082 });
0083 });
0084 });
0085
0086 describe('findObject3DNodes', () => {
0087 let root:THREE.Object3D, child1:THREE.Object3D, child2:THREE.Object3D, subchild1:THREE.Object3D, subchild2:THREE.Object3D;
0088
0089 beforeEach(() => {
0090 // Setup a mock hierarchy of THREE.Object3D nodes
0091 root = new THREE.Object3D();
0092 root.name = 'root';
0093
0094 child1 = new THREE.Object3D();
0095 child1.name = 'child1';
0096 root.add(child1);
0097
0098 child2 = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1));
0099 child2.name = 'child2';
0100 root.add(child2);
0101
0102 subchild1 = new THREE.Object3D();
0103 subchild1.name = 'subchild1';
0104 child1.add(subchild1);
0105
0106 subchild2 = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1));
0107 subchild2.name = 'match';
0108 child2.add(subchild2);
0109 });
0110
0111 it('should return all nodes when no pattern or type is provided', () => {
0112 const results = findObject3DNodes(root, '');
0113 expect(results.nodes.length).toBe(5);
0114 expect(results.deepestLevel).toBe(2);
0115 expect(results.totalWalked).toBe(5);
0116 });
0117
0118 it('should handle no matches found', () => {
0119 const results = findObject3DNodes(root, 'nonexistent');
0120 expect(results.nodes.length).toBe(0);
0121 });
0122
0123 it('should match nodes based on a pattern', () => {
0124 const results = findObject3DNodes(root, '**/match');
0125 expect(results.nodes.length).toBe(1);
0126 expect(results.nodes[0]).toBe(subchild2);
0127 expect(results.fullPaths[0]).toBe('root/child2/match');
0128 });
0129
0130 it('should filter nodes based on type', () => {
0131 const results = findObject3DNodes(root, '', 'Mesh');
0132 expect(results.nodes.every(node => node instanceof THREE.Mesh)).toBeTrue();
0133 expect(results.nodes.length).toBe(2); // Only child2 and subchild2 are Meshes
0134 });
0135
0136 it('should respect the maxLevel parameter', () => {
0137 const results = findObject3DNodes(root, '', '', 1);
0138 expect(results.deepestLevel).toBe(1);
0139 expect(results.totalWalked).toBe(3); // root, child1, child2
0140 });
0141
0142 it('should throw an error for invalid parentNode', () => {
0143 expect(() => {
0144 findObject3DNodes(null, '');
0145 }).toThrow();
0146 });
0147 });