// // Custom QUnit assertions. // /* global QUnit */ import { SmartComparer } from './SmartComparer'; import { ObjectLoader } from '../../src/loaders/ObjectLoader'; QUnit.assert.success = function ( message ) { // Equivalent to assert( true, message ); this.pushResult( { result: true, actual: undefined, expected: undefined, message: message } ); }; QUnit.assert.fail = function ( message ) { // Equivalent to assert( false, message ); this.pushResult( { result: false, actual: undefined, expected: undefined, message: message } ); }; QUnit.assert.numEqual = function ( actual, expected, message ) { var diff = Math.abs( actual - expected ); message = message || ( actual + " should be equal to " + expected ); this.pushResult( { result: diff < 0.1, actual: actual, expected: expected, message: message } ); }; QUnit.assert.equalKey = function ( obj, ref, key ) { var actual = obj[ key ]; var expected = ref[ key ]; var message = actual + ' should be equal to ' + expected + ' for key "' + key + '"'; this.pushResult( { result: actual == expected, actual: actual, expected: expected, message: message } ); }; QUnit.assert.smartEqual = function ( actual, expected, message ) { var cmp = new SmartComparer(); var same = cmp.areEqual( actual, expected ); var msg = cmp.getDiagnostic() || message; this.pushResult( { result: same, actual: actual, expected: expected, message: msg } ); }; // // GEOMETRY TEST HELPERS // function checkGeometryClone( geom ) { // Clone var copy = geom.clone(); QUnit.assert.notEqual( copy.uuid, geom.uuid, "clone uuid should differ from original" ); QUnit.assert.notEqual( copy.id, geom.id, "clone id should differ from original" ); var excludedProperties = [ 'parameters', 'widthSegments', 'heightSegments', 'depthSegments' ]; var differingProp = getDifferingProp( geom, copy, excludedProperties ); QUnit.assert.ok( differingProp === undefined, 'properties are equal' ); differingProp = getDifferingProp( copy, geom, excludedProperties ); QUnit.assert.ok( differingProp === undefined, 'properties are equal' ); // json round trip with clone checkGeometryJsonRoundtrip( copy ); } function getDifferingProp( geometryA, geometryB, excludedProperties ) { excludedProperties = excludedProperties || []; var geometryKeys = Object.keys( geometryA ); var cloneKeys = Object.keys( geometryB ); var differingProp = undefined; for ( var i = 0, l = geometryKeys.length; i < l; i ++ ) { var key = geometryKeys[ i ]; if ( excludedProperties.indexOf( key ) >= 0 ) continue; if ( cloneKeys.indexOf( key ) < 0 ) { differingProp = key; break; } } return differingProp; } // Compare json file with its source geometry. function checkGeometryJsonWriting( geom, json ) { QUnit.assert.equal( json.metadata.version, "4.5", "check metadata version" ); QUnit.assert.equalKey( geom, json, 'type' ); QUnit.assert.equalKey( geom, json, 'uuid' ); QUnit.assert.equal( json.id, undefined, "should not persist id" ); var params = geom.parameters; if ( ! params ) { return; } // All parameters from geometry should be persisted. var keys = Object.keys( params ); for ( var i = 0, l = keys.length; i < l; i ++ ) { QUnit.assert.equalKey( params, json, keys[ i ] ); } // All parameters from json should be transfered to the geometry. // json is flat. Ignore first level json properties that are not parameters. var notParameters = [ "metadata", "uuid", "type" ]; var keys = Object.keys( json ); for ( var i = 0, l = keys.length; i < l; i ++ ) { var key = keys[ i ]; if ( notParameters.indexOf( key ) === - 1 ) QUnit.assert.equalKey( params, json, key ); } } // Check parsing and reconstruction of json geometry function checkGeometryJsonReading( json, geom ) { var wrap = [ json ]; var loader = new ObjectLoader(); var output = loader.parseGeometries( wrap ); QUnit.assert.ok( output[ geom.uuid ], 'geometry matching source uuid not in output' ); // QUnit.assert.smartEqual( output[ geom.uuid ], geom, 'Reconstruct geometry from ObjectLoader' ); var differing = getDifferingProp( output[ geom.uuid ], geom, [ 'bones' ] ); if ( differing ) console.log( differing ); var excludedProperties = [ 'bones' ]; var differingProp = getDifferingProp( output[ geom.uuid ], geom, excludedProperties ); QUnit.assert.ok( differingProp === undefined, 'properties are equal' ); differingProp = getDifferingProp( geom, output[ geom.uuid ], excludedProperties ); QUnit.assert.ok( differingProp === undefined, 'properties are equal' ); } // Verify geom -> json -> geom function checkGeometryJsonRoundtrip( geom ) { var json = geom.toJSON(); checkGeometryJsonWriting( geom, json ); checkGeometryJsonReading( json, geom ); } // Look for undefined and NaN values in numerical fieds. function checkFinite( geom ) { var allVerticesAreFinite = true; var vertices = geom.vertices || []; for ( var i = 0, l = vertices.length; i < l; i ++ ) { var v = geom.vertices[ i ]; if ( ! ( isFinite( v.x ) || isFinite( v.y ) || isFinite( v.z ) ) ) { allVerticesAreFinite = false; break; } } // TODO Buffers, normal, etc. QUnit.assert.ok( allVerticesAreFinite, "contains only finite coordinates" ); } // Run common geometry tests. function runStdGeometryTests( assert, geometries ) { for ( var i = 0, l = geometries.length; i < l; i ++ ) { var geom = geometries[ i ]; checkFinite( geom ); // Clone checkGeometryClone( geom ); // json round trip checkGeometryJsonRoundtrip( geom ); } } // // LIGHT TEST HELPERS // // Run common light tests. function runStdLightTests( assert, lights ) { for ( var i = 0, l = lights.length; i < l; i ++ ) { var light = lights[ i ]; // copy and clone checkLightCopyClone( assert, light ); // THREE.Light doesn't get parsed by ObjectLoader as it's only // used as an abstract base class - so we skip the JSON tests if ( light.type !== "Light" ) { // json round trip checkLightJsonRoundtrip( assert, light ); } } } function checkLightCopyClone( assert, light ) { // copy var newLight = new light.constructor( 0xc0ffee ); newLight.copy( light ); QUnit.assert.notEqual( newLight.uuid, light.uuid, "Copied light's UUID differs from original" ); QUnit.assert.notEqual( newLight.id, light.id, "Copied light's id differs from original" ); QUnit.assert.smartEqual( newLight, light, "Copied light is equal to original" ); // real copy? newLight.color.setHex( 0xc0ffee ); QUnit.assert.notStrictEqual( newLight.color.getHex(), light.color.getHex(), "Copied light is independent from original" ); // Clone var clone = light.clone(); // better get a new var QUnit.assert.notEqual( clone.uuid, light.uuid, "Cloned light's UUID differs from original" ); QUnit.assert.notEqual( clone.id, light.id, "Clone light's id differs from original" ); QUnit.assert.smartEqual( clone, light, "Clone light is equal to original" ); // real clone? clone.color.setHex( 0xc0ffee ); QUnit.assert.notStrictEqual( clone.color.getHex(), light.color.getHex(), "Clone light is independent from original" ); if ( light.type !== "Light" ) { // json round trip with clone checkLightJsonRoundtrip( assert, clone ); } } // Compare json file with its source Light. function checkLightJsonWriting( assert, light, json ) { assert.equal( json.metadata.version, "4.5", "check metadata version" ); var object = json.object; assert.equalKey( light, object, 'type' ); assert.equalKey( light, object, 'uuid' ); assert.equal( object.id, undefined, "should not persist id" ); } // Check parsing and reconstruction of json Light function checkLightJsonReading( assert, json, light ) { var loader = new ObjectLoader(); var outputLight = loader.parse( json ); assert.smartEqual( outputLight, light, 'Reconstruct Light from ObjectLoader' ); } // Verify light -> json -> light function checkLightJsonRoundtrip( assert, light ) { var json = light.toJSON(); checkLightJsonWriting( assert, light, json ); checkLightJsonReading( assert, json, light ); } export { runStdLightTests, runStdGeometryTests };