diff options
Diffstat (limited to 'o3d/tests')
90 files changed, 12747 insertions, 0 deletions
diff --git a/o3d/tests/archive_files/BumpReflect.fx b/o3d/tests/archive_files/BumpReflect.fx new file mode 100644 index 0000000..684bc6d --- /dev/null +++ b/o3d/tests/archive_files/BumpReflect.fx @@ -0,0 +1,99 @@ +float4x4 world : World; +float4x4 worldInverseTranspose : WorldInverseTranspose; +float4x4 worldViewProj : WorldViewProjection; +float4x4 viewInverse : ViewInverse; + +//////////////// +// tweakables // +//////////////// + +float BumpHeight < + string UIName = "Bump Factor"; + float UIMin = 0.0; + float UIMax = 2.0; + float UIStep = 0.1; +> = 0.2; + +texture normalMap : Normal < + string UIName = "Normal Map"; + string name = "NMP_Ripples2_512.dds"; + string type = "2D"; +>; + +sampler2D NormalSampler = sampler_state { + Texture = <normalMap>; + MinFilter = Linear; + MagFilter = Linear; + MipFilter = Linear; +}; + +texture envMap : Environment < + string UIName = "Cube Map"; + string type = "CUBE"; + string name = "sunol_cubemap.dds"; +>; + +samplerCUBE EnvSampler = sampler_state { + Texture = <envMap>; + MinFilter = Linear; + MipFilter = Linear; + MagFilter = Linear; +// WrapS = ClampToEdge; +// WrapT = ClampToEdge; +}; + +//////////////// +// structures // +//////////////// + +struct a2v +{ + float4 Position : POSITION; //in object space + float3 TexCoord : TEXCOORD0; + float3 Tangent : TANGENT; // TANGENT; // ATTR14; // in object space + float3 Binormal : BINORMAL; // BINORMAL; // ATTR15; // in object space + float3 Normal : NORMAL; //in object space +}; + +struct v2f +{ + float4 Position : POSITION; //in projection space + float2 TexCoord : TEXCOORD0; + float3 worldEyeVec : TEXCOORD1; + float3 WorldNormal : TEXCOORD2; + float3 WorldTangent : TEXCOORD3; + float3 WorldBinorm : TEXCOORD4; +}; + +///////////// +// shaders // +///////////// + +v2f BumpReflectVS(a2v IN) +{ + v2f OUT; + OUT.Position = mul(IN.Position, worldViewProj); + OUT.TexCoord.xy = IN.TexCoord.xy; + OUT.WorldNormal = mul(float4(IN.Normal, 0), worldInverseTranspose).xyz; + OUT.WorldTangent = mul(float4(IN.Tangent, 0), worldInverseTranspose).xyz; + OUT.WorldBinorm = mul(float4(IN.Binormal, 0), worldInverseTranspose).xyz; + float3 worldPos = mul(IN.Position, world).xyz; + OUT.worldEyeVec = normalize(worldPos - viewInverse[3].xyz); + return OUT; +} + +float4 BumpReflectPS(v2f IN) : COLOR { + float2 bump = (tex2D(NormalSampler, IN.TexCoord.xy).xy * 2 - 1) * BumpHeight; + float3 normal = normalize(IN.WorldNormal); + float3 tangent = normalize(IN.WorldTangent); + float3 binormal = normalize(IN.WorldBinorm); + float3 nb = normal + bump.x * tangent + bump.y * binormal; + nb = normalize(nb); + float3 worldEyeVec = normalize(IN.worldEyeVec); + float3 lookup = reflect(worldEyeVec, nb); + return texCUBE(EnvSampler, float4(lookup, 1).xyz); +} + +// #o3d VertexShaderEntryPoint BumpReflectVS +// #o3d PixelShaderEntryPoint BumpReflectPS + diff --git a/o3d/tests/archive_files/bogus.tar.gz b/o3d/tests/archive_files/bogus.tar.gz new file mode 100644 index 0000000..989c181 --- /dev/null +++ b/o3d/tests/archive_files/bogus.tar.gz @@ -0,0 +1,4 @@ +fjdfijeifjeijfiejfijef +efifjeijfe +efislja;djfa +efkejslfra diff --git a/o3d/tests/archive_files/keyboard.jpg b/o3d/tests/archive_files/keyboard.jpg Binary files differnew file mode 100644 index 0000000..1fdba53 --- /dev/null +++ b/o3d/tests/archive_files/keyboard.jpg diff --git a/o3d/tests/archive_files/keyboard.jpg.gz b/o3d/tests/archive_files/keyboard.jpg.gz Binary files differnew file mode 100644 index 0000000..18ee068 --- /dev/null +++ b/o3d/tests/archive_files/keyboard.jpg.gz diff --git a/o3d/tests/archive_files/perc.aif b/o3d/tests/archive_files/perc.aif Binary files differnew file mode 100644 index 0000000..fc40178 --- /dev/null +++ b/o3d/tests/archive_files/perc.aif diff --git a/o3d/tests/archive_files/test1.tar b/o3d/tests/archive_files/test1.tar Binary files differnew file mode 100644 index 0000000..fe1e22d --- /dev/null +++ b/o3d/tests/archive_files/test1.tar diff --git a/o3d/tests/archive_files/test1.tar.gz b/o3d/tests/archive_files/test1.tar.gz Binary files differnew file mode 100644 index 0000000..9767501 --- /dev/null +++ b/o3d/tests/archive_files/test1.tar.gz diff --git a/o3d/tests/archive_files/test2.tar.gz b/o3d/tests/archive_files/test2.tar.gz Binary files differnew file mode 100644 index 0000000..4986e73 --- /dev/null +++ b/o3d/tests/archive_files/test2.tar.gz diff --git a/o3d/tests/basic_system_test/basic_system_test.cc b/o3d/tests/basic_system_test/basic_system_test.cc new file mode 100644 index 0000000..b37ac8e8 --- /dev/null +++ b/o3d/tests/basic_system_test/basic_system_test.cc @@ -0,0 +1,340 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// Basic O3D system test for constructing and rendering geometry. + +#include <math.h> + +#include "core/cross/client.h" +#include "core/cross/counter.h" +#include "core/cross/draw_context.h" +#include "core/cross/draw_pass.h" +#include "core/cross/draw_list.h" +#include "core/cross/primitive.h" +#include "core/cross/stream_bank.h" +#include "core/cross/tree_traversal.h" +#include "core/cross/clear_buffer.h" +#include "core/cross/math_utilities.h" +#include "import/cross/raw_data.h" +#include "tests/common/win/testing_common.h" +#include "tests/common/win/system_test.h" + +namespace o3d { + +float DegreesToRadians(float degrees) { + return degrees * kPi / 180.f; +} + +const char kShaderString[] = +"// World View Projection matrix that will transform the input vertices \n" +"// to screen space. \n" +"float4x4 worldViewProjection : WorldViewProjection; \n" +" \n" +"// input parameters for our vertex shader \n" +"struct VertexShaderInput { \n" +" float4 position : POSITION; \n" +"}; \n" +" \n" +"// input parameters for our pixel shader \n" +"struct PixelShaderInput { \n" +" float4 position : POSITION; \n" +"}; \n" +"/** \n" +"* The vertex shader simply transforms the input vertices to screen space. \n" +"*/ \n" +"PixelShaderInput vertexShaderFunction(VertexShaderInput input) { \n" +" PixelShaderInput output; \n" +" \n" +" // Multiply the vertex positions by the worldViewProjection matrix to \n" +" // transform them to screen space. \n" +" output.position = mul(input.position, worldViewProjection); \n" +" return output; \n" +"} \n" +" \n" +"/** \n" +"* This pixel shader just returns the color red. \n" +"*/ \n" +"float4 pixelShaderFunction(PixelShaderInput input): COLOR { \n" +" return float4(1, 0, 0, 1); // Red. \n" +"} \n" +" \n" +"// Here we tell our effect file *which* functions are \n" +"// our vertex and pixel shaders. \n" +" \n" +"// #o3d VertexShaderEntryPoint vertexShaderFunction \n" +"// #o3d PixelShaderEntryPoint pixelShaderFunction \n" +"// #o3d MatrixLoadOrder RowMajor \n"; + +// System-test class for basic o3d geometry construction and render +// functionality. +class BasicSystemTest : public testing::Test { + protected: + BasicSystemTest() + : object_manager_(g_service_locator) {} + + virtual void SetUp(); + virtual void TearDown(); + + Client* client() { + return client_; + } + + Pack* pack() { + return pack_; + } + + DrawContext* context() { + return context_; + } + + DrawList* opaque_draw_list() { + return opaque_draw_list_; + } + + DrawList* transparent_draw_list() { + return transparent_draw_list_; + } + + // Constructs a cube, and returns the transform node under which + // the new cube shape resides. + void CreateCube(Material::Ref material, Transform::Ref* transform); + + ServiceDependency<ObjectManager> object_manager_; + + private: + Client *client_; + Pack* pack_; + DrawContext* context_; + DrawList* opaque_draw_list_; + DrawList* transparent_draw_list_; +}; + +void BasicSystemTest::SetUp() { + client_ = new o3d::Client(g_service_locator); + client_->Init(); + + pack_ = object_manager_->CreatePack(); + + Transform* root = client_->root(); + + // Creates a clear buffer render node and parents it to the root. + ClearBuffer* clear_buffer = pack_->Create<ClearBuffer>(); + clear_buffer->set_priority(0); + clear_buffer->set_clear_color(Float4(0.5f, 0.5f, 0.5f, 1.0f)); + clear_buffer->SetParent(client_->render_graph_root()); + + // Create DrawLists + opaque_draw_list_ = pack_->Create<DrawList>(); + transparent_draw_list_ = pack_->Create<DrawList>(); + + // Create DrawContext. + context_ = pack_->Create<DrawContext>(); + + // Creates a TreeTraversal and parents it to the root. + TreeTraversal* tree_traversal = pack_->Create<TreeTraversal>(); + tree_traversal->set_priority(1); + tree_traversal->SetParent(client_->render_graph_root()); + + // Creates a DrawPass for opaque shapes. + DrawPass* opaque_draw_pass = pack_->Create<DrawPass>(); + opaque_draw_pass->set_priority(2); + opaque_draw_pass->set_draw_list(opaque_draw_list_); + opaque_draw_pass->SetParent(client_->render_graph_root()); + + // Creates a DrawPass for transparent shapes. + DrawPass* transparent_draw_pass = pack_->Create<DrawPass>(); + transparent_draw_pass->set_priority(3); + transparent_draw_pass->set_draw_list(transparent_draw_list_); + transparent_draw_pass->SetParent(client_->render_graph_root()); + + // Register the passlists and drawcontext with the TreeTraversal + tree_traversal->RegisterDrawList(opaque_draw_list_, context_, true); + tree_traversal->RegisterDrawList(transparent_draw_list_, context_, true); + tree_traversal->set_transform(root); + + const Point3 eye(0.0f, 1.0f, 5.0f); + const Point3 target(0.0f, 0.0f, 0.0f); + const Vector3 up(0.0f, 1.0f, 0.0f); + + const Matrix4 perspective_matrix = Vectormath::Aos::CreatePerspectiveMatrix( + DegreesToRadians(60.0f), + 1.0f, + 1.0f, + 1000.0f); + const Matrix4 view_matrix = Matrix4::lookAt(eye, target, up); + + context_->set_view(view_matrix); + context_->set_projection(perspective_matrix); +} + +void BasicSystemTest::TearDown() { + // Force another render to make the stream capture end. + client()->RenderClient(); + + pack_->Destroy(); + delete client_; +} + +void BasicSystemTest::CreateCube(Material::Ref material, + Transform::Ref* transform) { + Shape::Ref cube_shape(pack()->Create<Shape>()); + ASSERT_FALSE(cube_shape.IsNull()); + + Transform::Ref cube_xform(pack()->Create<Transform>()); + ASSERT_FALSE(cube_xform.IsNull()); + + // Create the Primitive that will contain the geometry data for + // the cube. + Primitive::Ref cube_primitive(pack()->Create<Primitive>()); + ASSERT_FALSE(cube_primitive.IsNull()); + + // Create a StreamBank to hold the streams of vertex data. + StreamBank::Ref stream_bank(pack()->Create<StreamBank>()); + ASSERT_FALSE(stream_bank.IsNull()); + + // Assign the material that was passed in to the primitive. + cube_primitive->set_material(material); + + // Assign the Primitive to the Shape. + cube_primitive->SetOwner(cube_shape); + + // Assign the StreamBank to the Primitive. + cube_primitive->set_stream_bank(stream_bank); + + cube_primitive->set_primitive_type(Primitive::TRIANGLELIST); + cube_primitive->set_number_primitives(12); // 12 triangles + cube_primitive->set_number_vertices(8); // 8 vertices in total + + cube_primitive->CreateDrawElement(pack(), NULL); + + static const float kPositionArray[][3] = { + {-0.5, -0.5, 0.5}, + {0.5, -0.5, 0.5}, + {-0.5, 0.5, 0.5}, + {0.5, 0.5, 0.5}, + {-0.5, 0.5, -0.5}, + {0.5, 0.5, -0.5}, + {-0.5, -0.5, -0.5}, + {0.5, -0.5, -0.5} + }; + + static const unsigned int kIndicesArray[] = { + 0, 1, 2, // face 1 + 2, 1, 3, + 2, 3, 4, // face 2 + 4, 3, 5, + 4, 5, 6, // face 3 + 6, 5, 7, + 6, 7, 0, // face 4 + 0, 7, 1, + 1, 7, 3, // face 5 + 3, 7, 5, + 6, 0, 4, // face 6 + 4, 0, 2 + }; + + static const unsigned int kNumComponents = arraysize(kPositionArray[0]); + static const unsigned int kNumElements = arraysize(kPositionArray); + static const unsigned int kStride = kNumComponents; + + VertexBuffer::Ref positions_buffer(pack()->Create<VertexBuffer>()); + + FloatField::Ref positions_field(positions_buffer->CreateField( + FloatField::GetApparentClass(), + 3)); + ASSERT_FALSE(positions_field.IsNull()); + + ASSERT_TRUE(positions_buffer->AllocateElements(kNumElements)); + positions_field->SetFromFloats(&kPositionArray[0][0], kStride, 0, + kNumElements); + + IndexBuffer::Ref index_buffer(pack()->Create<IndexBuffer>()); + ASSERT_FALSE(index_buffer.IsNull()); + + static const unsigned int kNumIndices = arraysize(kIndicesArray); + ASSERT_TRUE(index_buffer->AllocateElements(kNumIndices)); + index_buffer->index_field()->SetFromUInt32s(&kIndicesArray[0], 1, + 0, kNumIndices); + + // Associate the positions Buffer with the StreamBank. + stream_bank->SetVertexStream( + Stream::POSITION, // semantic: This stream stores vertex positions + 0, // semantic index: First (and only) position stream + positions_field, // field: the field this stream uses. + 0); // start_index: How many elements to skip in the + // field. + + // Associate the triangle indices Buffer with the primitive. + cube_primitive->set_index_buffer(index_buffer); + + cube_xform->AddShape(cube_shape); + *transform = cube_xform; +} + +TEST_F(BasicSystemTest, BasicSystemTestCase) { + ASSERT_FALSE(client()->root() == NULL); + + Transform *spin_transform = pack()->Create<Transform>(); + ASSERT_FALSE(spin_transform == NULL); + + Transform* root = client()->root(); + spin_transform->SetParent(root); + + Material::Ref cube_material(pack()->Create<Material>()); + ASSERT_FALSE(cube_material.IsNull()); + cube_material->set_draw_list(opaque_draw_list()); + + Effect::Ref effect(pack()->Create<Effect>()); + effect->LoadFromFXString(kShaderString); + cube_material->set_effect(effect); + + Transform::Ref cube_xform; + CreateCube(cube_material, &cube_xform); + ASSERT_FALSE(cube_xform.IsNull()); + cube_xform->SetParent(spin_transform); + + ASSERT_FALSE(spin_transform->GetChildren()[0] == NULL); + + // Assert that 5 rendered frames generate both the correct command streams, + // and framebuffer contents. + BEGIN_ASSERT_STREAM_CAPTURE(); + for (int frame_count = 0; frame_count < 5; ++frame_count) { + client()->RenderClient(); + ASSERT_FRAMEBUFFER(); + Matrix4 mat(Matrix4::rotationY(static_cast<float>(frame_count) * 2 * + static_cast<float>(M_PI) / 5.0f)); + spin_transform->set_local_matrix(mat); + } + END_ASSERT_STREAM_CAPTURE(); +} + +} // namespace o3d diff --git a/o3d/tests/basic_system_test/reference_frames/frame_capture0.png b/o3d/tests/basic_system_test/reference_frames/frame_capture0.png Binary files differnew file mode 100644 index 0000000..cfe991f --- /dev/null +++ b/o3d/tests/basic_system_test/reference_frames/frame_capture0.png diff --git a/o3d/tests/basic_system_test/reference_frames/frame_capture1.png b/o3d/tests/basic_system_test/reference_frames/frame_capture1.png Binary files differnew file mode 100644 index 0000000..3f7baeb --- /dev/null +++ b/o3d/tests/basic_system_test/reference_frames/frame_capture1.png diff --git a/o3d/tests/basic_system_test/reference_frames/frame_capture2.png b/o3d/tests/basic_system_test/reference_frames/frame_capture2.png Binary files differnew file mode 100644 index 0000000..b498023 --- /dev/null +++ b/o3d/tests/basic_system_test/reference_frames/frame_capture2.png diff --git a/o3d/tests/basic_system_test/reference_frames/frame_capture3.png b/o3d/tests/basic_system_test/reference_frames/frame_capture3.png Binary files differnew file mode 100644 index 0000000..fd5719c --- /dev/null +++ b/o3d/tests/basic_system_test/reference_frames/frame_capture3.png diff --git a/o3d/tests/basic_system_test/reference_frames/frame_capture4.png b/o3d/tests/basic_system_test/reference_frames/frame_capture4.png Binary files differnew file mode 100644 index 0000000..2fff834 --- /dev/null +++ b/o3d/tests/basic_system_test/reference_frames/frame_capture4.png diff --git a/o3d/tests/basic_system_test/reference_stream.csv b/o3d/tests/basic_system_test/reference_stream.csv new file mode 100644 index 0000000..eb38ab4 --- /dev/null +++ b/o3d/tests/basic_system_test/reference_stream.csv @@ -0,0 +1,242 @@ +Event Type,EID,Event,StartTime,Frame,Duration,FPS +Session Start,1,Start Session,0,,0, +Process Start,2,Start Process,0,,0, +Frame,3,Frame 2,30598216619,2,2655979068,0.4 +Call,4,D3DPERF_GetStatus(),30598284778,,, +User Marker,5,User Marker: Frame_Capture: 306 : tests\basic_system_test\import_test.cc,31097816048,,0, +User Marker,6,User Marker: CaptureScreenContents,31097864253,,0, +Call,7,"<0x041F4040> IDirect3DDevice9::GetRenderTarget(0x00000000, 0x003EBEC4 --> 0x041F4D40)",31097951090,,, +Call,8,<0x041F4040> IDirect3DDevice9::GetDepthStencilSurface(0x003EBEC8 --> 0x041C7D68),31097999717,,, +Call,9,<0x041F4040> IDirect3DDevice9::BeginScene(),31098043720,,, +Call,10,"<0x041F4040> IDirect3DDevice9::GetRenderTarget(0x00000000, 0x0012F3BC --> 0x041F4D40)",31098090625,,, +Call,11,<0x041F4D40> IDirect3DSurface9::GetDesc(0x0012F394),31098134913,,, +Call,12,<0x041F4D40> IDirect3DSurface9::Release(),31098179695,,, +Call,13,"<0x041F4040> IDirect3DDevice9::GetRenderTarget(0x00000000, 0x0012F3BC --> 0x041F4D40)",31098233507,,, +Call,14,<0x041F4D40> IDirect3DSurface9::GetDesc(0x0012F394),31098277332,,, +Call,15,<0x041F4D40> IDirect3DSurface9::Release(),31098320525,,, +Call,16,<0x041F4040> IDirect3DDevice9::SetViewport(0x0012F39C),31098365740,,, +Call,17,"<0x041F4040> IDirect3DDevice9::GetRenderTarget(0x00000000, 0x0012F6C8 --> 0x041F4D40)",31098432568,,, +Call,18,<0x041F4040> IDirect3DDevice9::GetDepthStencilSurface(0x0012F6BC --> 0x041C7D68),31098476648,,, +Call,19,"<0x041F4040> IDirect3DDevice9::Clear(0x00000000, NULL, 0x00000007, D3DCOLOR_ARGB(0xff,0x7f,0x7f,0x7f), 1.000f, 0x00000000)",31098521071,,, +Call,20,<0x041C7D68> IDirect3DSurface9::Release(),31098568276,,, +Call,21,<0x041F4D40> IDirect3DSurface9::Release(),31098611436,,, +Call,22,<0x041F4040> IDirect3DDevice9::SetIndices(0x041C85B8),31098727017,,, +Call,23,"<0x041F4040> IDirect3DDevice9::SetStreamSource(0, 0x041C84E8, 0, 12)",31098885293,,, +Call,24,<0x041F4040> IDirect3DDevice9::SetVertexDeclaration(0x041C8820),31098945447,,, +Call,25,"<0x041C8298> ID3DXEffect::SetMatrix(0xFAC1DD7B, 0x0012EECC)",31099004241,,, +Call,26,<0x041C8298> ID3DXEffect::GetTechnique(0),31099061461,,, +Call,27,<0x041C8298> ID3DXEffect::SetTechnique(0xFAC1D0CB),31099114543,,, +Call,28,"<0x041C8298> ID3DXEffect::Begin(0x0012EF60, 0x00000000)",31099167480,,, +Call,29,<0x041CACF0> IDirect3DStateBlock9::Capture(),31099185394,,, +Call,30,<0x041C9AB8> IDirect3DStateBlock9::Capture(),31099249010,,, +Call,31,<0x041C94E8> IDirect3DStateBlock9::Capture(),31099306834,,, +Call,32,<0x041CA088> IDirect3DStateBlock9::Capture(),31099362781,,, +Call,33,<0x041C8948> IDirect3DStateBlock9::Capture(),31099417686,,, +Call,34,<0x041C8298> ID3DXEffect::BeginPass(0),31099514400,,, +Call,35,<0x041F4040> IDirect3DDevice9::SetVertexShader(0x041C81E0),31099533107,,, +Call,36,"<0x041F4040> IDirect3DDevice9::SetVertexShaderConstantF(0, 0x053E22E0, 4)",31099588736,,, +Call,37,<0x041F4040> IDirect3DDevice9::SetPixelShader(0x041C8128),31099644021,,, +Call,38,"<0x041F4040> IDirect3DDevice9::DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12)",31099736770,,, +Call,39,<0x041C8298> ID3DXEffect::EndPass(),31099825615,,, +Call,40,<0x041C8298> ID3DXEffect::End(),31099887465,,, +Call,41,<0x041C8948> IDirect3DStateBlock9::Apply(),31099905619,,, +Call,42,<0x041CA088> IDirect3DStateBlock9::Apply(),31099959011,,, +Call,43,<0x041C94E8> IDirect3DStateBlock9::Apply(),31100002488,,, +Call,44,<0x041C9AB8> IDirect3DStateBlock9::Apply(),31100045426,,, +Call,45,<0x041CACF0> IDirect3DStateBlock9::Apply(),31100090448,,, +Call,46,<0x041F4040> IDirect3DDevice9::EndScene(),31100181906,,, +Call,47,<0x041F4D40> IDirect3DSurface9::Release(),31100226786,,, +Call,48,<0x041C7D68> IDirect3DSurface9::Release(),31100271023,,, +Call,49,"<0x041F4040> IDirect3DDevice9::Present(NULL, NULL, NULL, NULL)",31100330032,,, +Frame,50,Frame 3,33254239772,3,2655502064,0.4 +Call,51,D3DPERF_GetStatus(),33254341389,,, +User Marker,52,User Marker: Frame_Capture: 306 : tests\basic_system_test\import_test.cc,33754093579,,0, +User Marker,53,User Marker: CaptureScreenContents,33754168712,,0, +Call,54,"<0x041F4040> IDirect3DDevice9::GetRenderTarget(0x00000000, 0x003EBEC4 --> 0x041F4D40)",33754242875,,, +Call,55,<0x041F4040> IDirect3DDevice9::GetDepthStencilSurface(0x003EBEC8 --> 0x041C7D68),33754291635,,, +Call,56,<0x041F4040> IDirect3DDevice9::BeginScene(),33754335630,,, +Call,57,"<0x041F4040> IDirect3DDevice9::GetRenderTarget(0x00000000, 0x0012F3BC --> 0x041F4D40)",33754382330,,, +Call,58,<0x041F4D40> IDirect3DSurface9::GetDesc(0x0012F394),33754426625,,, +Call,59,<0x041F4D40> IDirect3DSurface9::Release(),33754471340,,, +Call,60,"<0x041F4040> IDirect3DDevice9::GetRenderTarget(0x00000000, 0x0012F3BC --> 0x041F4D40)",33754516463,,, +Call,61,<0x041F4D40> IDirect3DSurface9::GetDesc(0x0012F394),33754560173,,, +Call,62,<0x041F4D40> IDirect3DSurface9::Release(),33754603635,,, +Call,63,<0x041F4040> IDirect3DDevice9::SetViewport(0x0012F39C),33754648955,,, +Call,64,"<0x041F4040> IDirect3DDevice9::GetRenderTarget(0x00000000, 0x0012F6C8 --> 0x041F4D40)",33754715152,,, +Call,65,<0x041F4040> IDirect3DDevice9::GetDepthStencilSurface(0x0012F6BC --> 0x041C7D68),33754758979,,, +Call,66,"<0x041F4040> IDirect3DDevice9::Clear(0x00000000, NULL, 0x00000007, D3DCOLOR_ARGB(0xff,0x7f,0x7f,0x7f), 1.000f, 0x00000000)",33754803029,,, +Call,67,<0x041C7D68> IDirect3DSurface9::Release(),33754858946,,, +Call,68,<0x041F4D40> IDirect3DSurface9::Release(),33754902321,,, +Call,69,<0x041F4040> IDirect3DDevice9::SetIndices(0x041C85B8),33755087163,,, +Call,70,"<0x041F4040> IDirect3DDevice9::SetStreamSource(0, 0x041C84E8, 0, 12)",33755142683,,, +Call,71,<0x041F4040> IDirect3DDevice9::SetVertexDeclaration(0x041C8820),33755189392,,, +Call,72,"<0x041C8298> ID3DXEffect::SetMatrix(0xFAC1DD7B, 0x0012EECC)",33755236937,,, +Call,73,<0x041C8298> ID3DXEffect::GetTechnique(0),33755282727,,, +Call,74,<0x041C8298> ID3DXEffect::SetTechnique(0xFAC1D0CB),33755325955,,, +Call,75,"<0x041C8298> ID3DXEffect::Begin(0x0012EF60, 0x00000000)",33755369875,,, +Call,76,<0x041CACF0> IDirect3DStateBlock9::Capture(),33755384392,,, +Call,77,<0x041C9AB8> IDirect3DStateBlock9::Capture(),33755431049,,, +Call,78,<0x041C94E8> IDirect3DStateBlock9::Capture(),33755475384,,, +Call,79,<0x041CA088> IDirect3DStateBlock9::Capture(),33755518354,,, +Call,80,<0x041C8948> IDirect3DStateBlock9::Capture(),33755561217,,, +Call,81,<0x041C8298> ID3DXEffect::BeginPass(0),33755635633,,, +Call,82,<0x041F4040> IDirect3DDevice9::SetVertexShader(0x041C81E0),33755651344,,, +Call,83,"<0x041F4040> IDirect3DDevice9::SetVertexShaderConstantF(0, 0x053E22E0, 4)",33755697184,,, +Call,84,<0x041F4040> IDirect3DDevice9::SetPixelShader(0x041C8128),33755742764,,, +Call,85,"<0x041F4040> IDirect3DDevice9::DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12)",33755818852,,, +Call,86,<0x041C8298> ID3DXEffect::EndPass(),33755867400,,, +Call,87,<0x041C8298> ID3DXEffect::End(),33755910380,,, +Call,88,<0x041C8948> IDirect3DStateBlock9::Apply(),33755923289,,, +Call,89,<0x041CA088> IDirect3DStateBlock9::Apply(),33755988713,,, +Call,90,<0x041C94E8> IDirect3DStateBlock9::Apply(),33756051677,,, +Call,91,<0x041C9AB8> IDirect3DStateBlock9::Apply(),33756095407,,, +Call,92,<0x041CACF0> IDirect3DStateBlock9::Apply(),33756140752,,, +Call,93,<0x041F4040> IDirect3DDevice9::EndScene(),33756230874,,, +Call,94,<0x041F4D40> IDirect3DSurface9::Release(),33756275152,,, +Call,95,<0x041C7D68> IDirect3DSurface9::Release(),33756318974,,, +Call,96,"<0x041F4040> IDirect3DDevice9::Present(NULL, NULL, NULL, NULL)",33756374044,,, +Frame,97,Frame 4,35909807940,4,2701946354,0.4 +Call,98,D3DPERF_GetStatus(),35909909042,,, +User Marker,99,User Marker: Frame_Capture: 306 : tests\basic_system_test\import_test.cc,36409267444,,0, +User Marker,100,User Marker: CaptureScreenContents,36409356534,,0, +Call,101,"<0x041F4040> IDirect3DDevice9::GetRenderTarget(0x00000000, 0x003EBEC4 --> 0x041F4D40)",36409433720,,, +Call,102,<0x041F4040> IDirect3DDevice9::GetDepthStencilSurface(0x003EBEC8 --> 0x041C7D68),36409482529,,, +Call,103,<0x041F4040> IDirect3DDevice9::BeginScene(),36409526599,,, +Call,104,"<0x041F4040> IDirect3DDevice9::GetRenderTarget(0x00000000, 0x0012F3BC --> 0x041F4D40)",36409573357,,, +Call,105,<0x041F4D40> IDirect3DSurface9::GetDesc(0x0012F394),36409617609,,, +Call,106,<0x041F4D40> IDirect3DSurface9::Release(),36409662462,,, +Call,107,"<0x041F4040> IDirect3DDevice9::GetRenderTarget(0x00000000, 0x0012F3BC --> 0x041F4D40)",36409707537,,, +Call,108,<0x041F4D40> IDirect3DSurface9::GetDesc(0x0012F394),36409750972,,, +Call,109,<0x041F4D40> IDirect3DSurface9::Release(),36409794277,,, +Call,110,<0x041F4040> IDirect3DDevice9::SetViewport(0x0012F39C),36409839547,,, +Call,111,"<0x041F4040> IDirect3DDevice9::GetRenderTarget(0x00000000, 0x0012F6C8 --> 0x041F4D40)",36409906133,,, +Call,112,<0x041F4040> IDirect3DDevice9::GetDepthStencilSurface(0x0012F6BC --> 0x041C7D68),36409950343,,, +Call,113,"<0x041F4040> IDirect3DDevice9::Clear(0x00000000, NULL, 0x00000007, D3DCOLOR_ARGB(0xff,0x7f,0x7f,0x7f), 1.000f, 0x00000000)",36409994496,,, +Call,114,<0x041C7D68> IDirect3DSurface9::Release(),36410040548,,, +Call,115,<0x041F4D40> IDirect3DSurface9::Release(),36410083603,,, +Call,116,<0x041F4040> IDirect3DDevice9::SetIndices(0x041C85B8),36410199387,,, +Call,117,"<0x041F4040> IDirect3DDevice9::SetStreamSource(0, 0x041C84E8, 0, 12)",36410296534,,, +Call,118,<0x041F4040> IDirect3DDevice9::SetVertexDeclaration(0x041C8820),36410343771,,, +Call,119,"<0x041C8298> ID3DXEffect::SetMatrix(0xFAC1DD7B, 0x0012EECC)",36410391106,,, +Call,120,<0x041C8298> ID3DXEffect::GetTechnique(0),36410437171,,, +Call,121,<0x041C8298> ID3DXEffect::SetTechnique(0xFAC1D0CB),36410573271,,, +Call,122,"<0x041C8298> ID3DXEffect::Begin(0x0012EF60, 0x00000000)",36410618823,,, +Call,123,<0x041CACF0> IDirect3DStateBlock9::Capture(),36410633515,,, +Call,124,<0x041C9AB8> IDirect3DStateBlock9::Capture(),36410680440,,, +Call,125,<0x041C94E8> IDirect3DStateBlock9::Capture(),36410725060,,, +Call,126,<0x041CA088> IDirect3DStateBlock9::Capture(),36410768165,,, +Call,127,<0x041C8948> IDirect3DStateBlock9::Capture(),36410811430,,, +Call,128,<0x041C8298> ID3DXEffect::BeginPass(0),36410886131,,, +Call,129,<0x041F4040> IDirect3DDevice9::SetVertexShader(0x041C81E0),36410901798,,, +Call,130,"<0x041F4040> IDirect3DDevice9::SetVertexShaderConstantF(0, 0x053E22E0, 4)",36410947800,,, +Call,131,<0x041F4040> IDirect3DDevice9::SetPixelShader(0x041C8128),36410993338,,, +Call,132,"<0x041F4040> IDirect3DDevice9::DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12)",36411069298,,, +Call,133,<0x041C8298> ID3DXEffect::EndPass(),36411117723,,, +Call,134,<0x041C8298> ID3DXEffect::End(),36411160953,,, +Call,135,<0x041C8948> IDirect3DStateBlock9::Apply(),36411174055,,, +Call,136,<0x041CA088> IDirect3DStateBlock9::Apply(),36411299753,,, +Call,137,<0x041C94E8> IDirect3DStateBlock9::Apply(),36411354450,,, +Call,138,<0x041C9AB8> IDirect3DStateBlock9::Apply(),36411407984,,, +Call,139,<0x041CACF0> IDirect3DStateBlock9::Apply(),36411463799,,, +Call,140,<0x041F4040> IDirect3DDevice9::EndScene(),36411573417,,, +Call,141,<0x041F4D40> IDirect3DSurface9::Release(),36411627859,,, +Call,142,<0x041C7D68> IDirect3DSurface9::Release(),36411680366,,, +Call,143,"<0x041F4040> IDirect3DDevice9::Present(NULL, NULL, NULL, NULL)",36411737183,,, +Frame,144,Frame 5,38611822165,5,2704679664,0.4 +Call,145,D3DPERF_GetStatus(),38611921000,,, +User Marker,146,User Marker: Frame_Capture: 306 : tests\basic_system_test\import_test.cc,39111379596,,0, +User Marker,147,User Marker: CaptureScreenContents,39111440170,,0, +Call,148,"<0x041F4040> IDirect3DDevice9::GetRenderTarget(0x00000000, 0x003EBEC4 --> 0x041F4D40)",39111536980,,, +Call,149,<0x041F4040> IDirect3DDevice9::GetDepthStencilSurface(0x003EBEC8 --> 0x041C7D68),39111596751,,, +Call,150,<0x041F4040> IDirect3DDevice9::BeginScene(),39111652673,,, +Call,151,"<0x041F4040> IDirect3DDevice9::GetRenderTarget(0x00000000, 0x0012F3BC --> 0x041F4D40)",39111709028,,, +Call,152,<0x041F4D40> IDirect3DSurface9::GetDesc(0x0012F394),39111762947,,, +Call,153,<0x041F4D40> IDirect3DSurface9::Release(),39111820274,,, +Call,154,"<0x041F4040> IDirect3DDevice9::GetRenderTarget(0x00000000, 0x0012F3BC --> 0x041F4D40)",39111884080,,, +Call,155,<0x041F4D40> IDirect3DSurface9::GetDesc(0x0012F394),39111938522,,, +Call,156,<0x041F4D40> IDirect3DSurface9::Release(),39111981857,,, +Call,157,<0x041F4040> IDirect3DDevice9::SetViewport(0x0012F39C),39112027207,,, +Call,158,"<0x041F4040> IDirect3DDevice9::GetRenderTarget(0x00000000, 0x0012F6C8 --> 0x041F4D40)",39112093744,,, +Call,159,<0x041F4040> IDirect3DDevice9::GetDepthStencilSurface(0x0012F6BC --> 0x041C7D68),39112137584,,, +Call,160,"<0x041F4040> IDirect3DDevice9::Clear(0x00000000, NULL, 0x00000007, D3DCOLOR_ARGB(0xff,0x7f,0x7f,0x7f), 1.000f, 0x00000000)",39112181704,,, +Call,161,<0x041C7D68> IDirect3DSurface9::Release(),39112227771,,, +Call,162,<0x041F4D40> IDirect3DSurface9::Release(),39112270774,,, +Call,163,<0x041F4040> IDirect3DDevice9::SetIndices(0x041C85B8),39112405776,,, +Call,164,"<0x041F4040> IDirect3DDevice9::SetStreamSource(0, 0x041C84E8, 0, 12)",39112461208,,, +Call,165,<0x041F4040> IDirect3DDevice9::SetVertexDeclaration(0x041C8820),39112507971,,, +Call,166,"<0x041C8298> ID3DXEffect::SetMatrix(0xFAC1DD7B, 0x0012EECC)",39112555123,,, +Call,167,<0x041C8298> ID3DXEffect::GetTechnique(0),39112601068,,, +Call,168,<0x041C8298> ID3DXEffect::SetTechnique(0xFAC1D0CB),39112644503,,, +Call,169,"<0x041C8298> ID3DXEffect::Begin(0x0012EF60, 0x00000000)",39112688565,,, +Call,170,<0x041CACF0> IDirect3DStateBlock9::Capture(),39112703112,,, +Call,171,<0x041C9AB8> IDirect3DStateBlock9::Capture(),39112749709,,, +Call,172,<0x041C94E8> IDirect3DStateBlock9::Capture(),39112794005,,, +Call,173,<0x041CA088> IDirect3DStateBlock9::Capture(),39112837254,,, +Call,174,<0x041C8948> IDirect3DStateBlock9::Capture(),39112880402,,, +Call,175,<0x041C8298> ID3DXEffect::BeginPass(0),39112955206,,, +Call,176,<0x041F4040> IDirect3DDevice9::SetVertexShader(0x041C81E0),39112970822,,, +Call,177,"<0x041F4040> IDirect3DDevice9::SetVertexShaderConstantF(0, 0x053E22E0, 4)",39113026769,,, +Call,178,<0x041F4040> IDirect3DDevice9::SetPixelShader(0x041C8128),39113072436,,, +Call,179,"<0x041F4040> IDirect3DDevice9::DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12)",39113148480,,, +Call,180,<0x041C8298> ID3DXEffect::EndPass(),39113196757,,, +Call,181,<0x041C8298> ID3DXEffect::End(),39113239885,,, +Call,182,<0x041C8948> IDirect3DStateBlock9::Apply(),39113252804,,, +Call,183,<0x041CA088> IDirect3DStateBlock9::Apply(),39113297209,,, +Call,184,<0x041C94E8> IDirect3DStateBlock9::Apply(),39113370402,,, +Call,185,<0x041C9AB8> IDirect3DStateBlock9::Apply(),39113423302,,, +Call,186,<0x041CACF0> IDirect3DStateBlock9::Apply(),39113468437,,, +Call,187,<0x041F4040> IDirect3DDevice9::EndScene(),39113556772,,, +Call,188,<0x041F4D40> IDirect3DSurface9::Release(),39113600702,,, +Call,189,<0x041C7D68> IDirect3DSurface9::Release(),39113644717,,, +Call,190,"<0x041F4040> IDirect3DDevice9::Present(NULL, NULL, NULL, NULL)",39113702049,,, +Frame,191,Frame 6,41316567158,6,2768584865,0.4 +Call,192,D3DPERF_GetStatus(),41316651078,,, +User Marker,193,User Marker: Frame_Capture: 306 : tests\basic_system_test\import_test.cc,41816443226,,0, +User Marker,194,User Marker: CaptureScreenContents,41816519169,,0, +Call,195,D3DPERF_GetStatus(),41816586445,,, +User Marker,196,User Marker: EndCommandStreamCapture,41816632693,,0, +Call,197,"<0x041F4040> IDirect3DDevice9::GetRenderTarget(0x00000000, 0x003EBEC4 --> 0x041F4D40)",41816688500,,, +Call,198,<0x041F4040> IDirect3DDevice9::GetDepthStencilSurface(0x003EBEC8 --> 0x041C7D68),41816735932,,, +Call,199,<0x041F4040> IDirect3DDevice9::BeginScene(),41816779852,,, +Call,200,"<0x041F4040> IDirect3DDevice9::GetRenderTarget(0x00000000, 0x0012F558 --> 0x041F4D40)",41816826552,,, +Call,201,<0x041F4D40> IDirect3DSurface9::GetDesc(0x0012F530),41816870777,,, +Call,202,<0x041F4D40> IDirect3DSurface9::Release(),41816915274,,, +Call,203,"<0x041F4040> IDirect3DDevice9::GetRenderTarget(0x00000000, 0x0012F558 --> 0x041F4D40)",41816960532,,, +Call,204,<0x041F4D40> IDirect3DSurface9::GetDesc(0x0012F530),41817004137,,, +Call,205,<0x041F4D40> IDirect3DSurface9::Release(),41817047360,,, +Call,206,<0x041F4040> IDirect3DDevice9::SetViewport(0x0012F538),41817092544,,, +Call,207,"<0x041F4040> IDirect3DDevice9::GetRenderTarget(0x00000000, 0x0012F864 --> 0x041F4D40)",41817159118,,, +Call,208,<0x041F4040> IDirect3DDevice9::GetDepthStencilSurface(0x0012F858 --> 0x041C7D68),41817203298,,, +Call,209,"<0x041F4040> IDirect3DDevice9::Clear(0x00000000, NULL, 0x00000007, D3DCOLOR_ARGB(0xff,0x7f,0x7f,0x7f), 1.000f, 0x00000000)",41817247511,,, +Call,210,<0x041C7D68> IDirect3DSurface9::Release(),41817293471,,, +Call,211,<0x041F4D40> IDirect3DSurface9::Release(),41817336286,,, +Call,212,<0x041F4040> IDirect3DDevice9::SetIndices(0x041C85B8),41817458434,,, +Call,213,"<0x041F4040> IDirect3DDevice9::SetStreamSource(0, 0x041C84E8, 0, 12)",41817509654,,, +Call,214,<0x041F4040> IDirect3DDevice9::SetVertexDeclaration(0x041C8820),41817556511,,, +Call,215,"<0x041C8298> ID3DXEffect::SetMatrix(0xFAC1DD7B, 0x0012F068)",41817604223,,, +Call,216,<0x041C8298> ID3DXEffect::GetTechnique(0),41817649908,,, +Call,217,<0x041C8298> ID3DXEffect::SetTechnique(0xFAC1D0CB),41817693486,,, +Call,218,"<0x041C8298> ID3DXEffect::Begin(0x0012F0FC, 0x00000000)",41817737806,,, +Call,219,<0x041CACF0> IDirect3DStateBlock9::Capture(),41817752540,,, +Call,220,<0x041C9AB8> IDirect3DStateBlock9::Capture(),41817799022,,, +Call,221,<0x041C94E8> IDirect3DStateBlock9::Capture(),41817843227,,, +Call,222,<0x041CA088> IDirect3DStateBlock9::Capture(),41817886413,,, +Call,223,<0x041C8948> IDirect3DStateBlock9::Capture(),41817929598,,, +Call,224,<0x041C8298> ID3DXEffect::BeginPass(0),41818003948,,, +Call,225,<0x041F4040> IDirect3DDevice9::SetVertexShader(0x041C81E0),41818019610,,, +Call,226,"<0x041F4040> IDirect3DDevice9::SetVertexShaderConstantF(0, 0x053E22E0, 4)",41818065208,,, +Call,227,<0x041F4040> IDirect3DDevice9::SetPixelShader(0x041C8128),41818110687,,, +Call,228,"<0x041F4040> IDirect3DDevice9::DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12)",41818186683,,, +Call,229,<0x041C8298> ID3DXEffect::EndPass(),41818234970,,, +Call,230,<0x041C8298> ID3DXEffect::End(),41818278298,,, +Call,231,<0x041C8948> IDirect3DStateBlock9::Apply(),41818291347,,, +Call,232,<0x041CA088> IDirect3DStateBlock9::Apply(),41818378780,,, +Call,233,<0x041C94E8> IDirect3DStateBlock9::Apply(),41818435942,,, +Call,234,<0x041C9AB8> IDirect3DStateBlock9::Apply(),41818479202,,, +Call,235,<0x041CACF0> IDirect3DStateBlock9::Apply(),41818523972,,, +Call,236,<0x041F4040> IDirect3DDevice9::EndScene(),41818612302,,, +Call,237,<0x041F4D40> IDirect3DSurface9::Release(),41818656510,,, +Call,238,<0x041C7D68> IDirect3DSurface9::Release(),41818700222,,, +Call,239,"<0x041F4040> IDirect3DDevice9::Present(NULL, NULL, NULL, NULL)",41818754391,,, +Process End,240,End Process,44103702736,,0, +Session End,241,End Session,44103702736,,0, diff --git a/o3d/tests/bitmap_test/5kx5k.dds b/o3d/tests/bitmap_test/5kx5k.dds Binary files differnew file mode 100644 index 0000000..626845b --- /dev/null +++ b/o3d/tests/bitmap_test/5kx5k.dds diff --git a/o3d/tests/bitmap_test/5kx5k.jpg b/o3d/tests/bitmap_test/5kx5k.jpg Binary files differnew file mode 100644 index 0000000..2395bb3 --- /dev/null +++ b/o3d/tests/bitmap_test/5kx5k.jpg diff --git a/o3d/tests/bitmap_test/5kx5k.png b/o3d/tests/bitmap_test/5kx5k.png Binary files differnew file mode 100644 index 0000000..458ac24 --- /dev/null +++ b/o3d/tests/bitmap_test/5kx5k.png diff --git a/o3d/tests/bitmap_test/5kx5k.tga b/o3d/tests/bitmap_test/5kx5k.tga Binary files differnew file mode 100644 index 0000000..2db7349 --- /dev/null +++ b/o3d/tests/bitmap_test/5kx5k.tga diff --git a/o3d/tests/bitmap_test/dds-dxt1-256x256-alpha.dds b/o3d/tests/bitmap_test/dds-dxt1-256x256-alpha.dds Binary files differnew file mode 100644 index 0000000..79c1c19 --- /dev/null +++ b/o3d/tests/bitmap_test/dds-dxt1-256x256-alpha.dds diff --git a/o3d/tests/bitmap_test/dds-dxt1-256x256-mipmap.dds b/o3d/tests/bitmap_test/dds-dxt1-256x256-mipmap.dds Binary files differnew file mode 100644 index 0000000..921cab3 --- /dev/null +++ b/o3d/tests/bitmap_test/dds-dxt1-256x256-mipmap.dds diff --git a/o3d/tests/bitmap_test/dds-dxt1-256x256.dds b/o3d/tests/bitmap_test/dds-dxt1-256x256.dds Binary files differnew file mode 100644 index 0000000..f5e60e2 --- /dev/null +++ b/o3d/tests/bitmap_test/dds-dxt1-256x256.dds diff --git a/o3d/tests/bitmap_test/dds-dxt3-256x256-alpha.dds b/o3d/tests/bitmap_test/dds-dxt3-256x256-alpha.dds Binary files differnew file mode 100644 index 0000000..f7086b4 --- /dev/null +++ b/o3d/tests/bitmap_test/dds-dxt3-256x256-alpha.dds diff --git a/o3d/tests/bitmap_test/dds-dxt3-256x256-mipmap.dds b/o3d/tests/bitmap_test/dds-dxt3-256x256-mipmap.dds Binary files differnew file mode 100644 index 0000000..a72239c --- /dev/null +++ b/o3d/tests/bitmap_test/dds-dxt3-256x256-mipmap.dds diff --git a/o3d/tests/bitmap_test/dds-dxt5-256x256-alpha.dds b/o3d/tests/bitmap_test/dds-dxt5-256x256-alpha.dds Binary files differnew file mode 100644 index 0000000..388d000 --- /dev/null +++ b/o3d/tests/bitmap_test/dds-dxt5-256x256-alpha.dds diff --git a/o3d/tests/bitmap_test/dds-dxt5-256x256-mipmap.dds b/o3d/tests/bitmap_test/dds-dxt5-256x256-mipmap.dds Binary files differnew file mode 100644 index 0000000..45b6869 --- /dev/null +++ b/o3d/tests/bitmap_test/dds-dxt5-256x256-mipmap.dds diff --git a/o3d/tests/bitmap_test/gif-256x256-interlaced.gif b/o3d/tests/bitmap_test/gif-256x256-interlaced.gif Binary files differnew file mode 100644 index 0000000..7d8498e --- /dev/null +++ b/o3d/tests/bitmap_test/gif-256x256-interlaced.gif diff --git a/o3d/tests/bitmap_test/gif-256x256.gif b/o3d/tests/bitmap_test/gif-256x256.gif Binary files differnew file mode 100644 index 0000000..fa81387 --- /dev/null +++ b/o3d/tests/bitmap_test/gif-256x256.gif diff --git a/o3d/tests/bitmap_test/jpeg-256x256.jpg b/o3d/tests/bitmap_test/jpeg-256x256.jpg Binary files differnew file mode 100644 index 0000000..ae4448c --- /dev/null +++ b/o3d/tests/bitmap_test/jpeg-256x256.jpg diff --git a/o3d/tests/bitmap_test/png-256x256-24bit-interlaced.png b/o3d/tests/bitmap_test/png-256x256-24bit-interlaced.png Binary files differnew file mode 100644 index 0000000..37663d4 --- /dev/null +++ b/o3d/tests/bitmap_test/png-256x256-24bit-interlaced.png diff --git a/o3d/tests/bitmap_test/png-256x256-24bit.png b/o3d/tests/bitmap_test/png-256x256-24bit.png Binary files differnew file mode 100644 index 0000000..126dab8 --- /dev/null +++ b/o3d/tests/bitmap_test/png-256x256-24bit.png diff --git a/o3d/tests/bitmap_test/png-256x256-32bit.png b/o3d/tests/bitmap_test/png-256x256-32bit.png Binary files differnew file mode 100644 index 0000000..8f858f9 --- /dev/null +++ b/o3d/tests/bitmap_test/png-256x256-32bit.png diff --git a/o3d/tests/bitmap_test/png-256x256-8bit-palette-alpha.png b/o3d/tests/bitmap_test/png-256x256-8bit-palette-alpha.png Binary files differnew file mode 100644 index 0000000..35b61a9 --- /dev/null +++ b/o3d/tests/bitmap_test/png-256x256-8bit-palette-alpha.png diff --git a/o3d/tests/bitmap_test/png-256x256-8bit-palette.png b/o3d/tests/bitmap_test/png-256x256-8bit-palette.png Binary files differnew file mode 100644 index 0000000..7134cf7 --- /dev/null +++ b/o3d/tests/bitmap_test/png-256x256-8bit-palette.png diff --git a/o3d/tests/bitmap_test/test_source.psd b/o3d/tests/bitmap_test/test_source.psd Binary files differnew file mode 100644 index 0000000..cd67ce4 --- /dev/null +++ b/o3d/tests/bitmap_test/test_source.psd diff --git a/o3d/tests/bitmap_test/tga-256x256-24bit.tga b/o3d/tests/bitmap_test/tga-256x256-24bit.tga Binary files differnew file mode 100644 index 0000000..5619323 --- /dev/null +++ b/o3d/tests/bitmap_test/tga-256x256-24bit.tga diff --git a/o3d/tests/bitmap_test/tga-256x256-32bit.tga b/o3d/tests/bitmap_test/tga-256x256-32bit.tga Binary files differnew file mode 100644 index 0000000..1d20f8c --- /dev/null +++ b/o3d/tests/bitmap_test/tga-256x256-32bit.tga diff --git a/o3d/tests/build.scons b/o3d/tests/build.scons new file mode 100644 index 0000000..c6b41a9 --- /dev/null +++ b/o3d/tests/build.scons @@ -0,0 +1,706 @@ +# Copyright 2009, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +import os +import sys + +Import('env') + +env['COMPONENT_TEST_SUBSYSTEM_WINDOWS'] = True + +if env.Bit('windows'): + # gmock on MSVC currently has 3 issues: + # - it needs <tuple>, that MSVC doesn't have. We could use boost for that + # - the 1.0.0 version triggers a bug in MSVC where function-local template + # types cause duplicate symbols. It may be fixed in a more recent release. + # - on MSVC, it triggers a bug where it gets confused between chrome's and + # gmock's version of down_cast. + use_gmock = False +else: + use_gmock = True + +gtest_env = env.Clone() +gtest_env.Append( + CPPPATH = ['$GTEST_DIR/include', + '$GTEST_DIR', + ] +) +gtest_sources = [ + 'gtest-all', +] +gtest_objs = [gtest_env.ComponentObject(name, '$GTEST_DIR/src/%s.cc' % name) + for name in gtest_sources] + +if use_gmock: + gmock_env = gtest_env.Clone() + gmock_env.Append(CPPPATH = ['$GMOCK_DIR/include', + '$GMOCK_DIR']) + gmock_sources = ['gmock-all'] + gtest_objs += [gmock_env.ComponentObject(name, '$GMOCK_DIR/src/%s.cc' % name) + for name in gmock_sources] +gtest_lib = gtest_env.Library('gtest', gtest_objs) + +env.Append( + CPPDEFINES = [ + '_USE_MATH_DEFINES', + ], + CPPPATH = [ + env.Dir('$COLLADA_DIR'), + env.Dir('$COLLADA_DIR/LibXML/include'), + env.Dir('$CG_DIR/include'), + # Headers for Antlr runtime library + env.Dir('$ANTLRLIBC_DIR/include'), + # Headers generated by Antlr for Technique grammar + env.Dir('$OBJ_ROOT/compiler/technique'), + '$GTEST_DIR/include', + '$GMOCK_DIR/include', + ], + LIBPATH=[ + env.Dir('.'), + env.Dir('$NACL_LIB_DIR'), + env.Dir('$OBJ_ROOT/compiler/technique'), # For technique library + env.Dir('$OBJ_ROOT/compiler/antlr'), # For antlr3c library + ], +) +# TODO: rearrange coverage so this can be an append. + +# NOTE: Do not rearrange or sort these -- order is +# (apparently) important here on Linux. +env.Prepend( + LIBS = [ + 'testing_common', + 'o3dImportNoConditioner', + 'o3dCore', + 'o3dImport', + 'o3dArchive', + 'o3dCorePlatform', + 'o3dSerializer', + 'o3dUtils', + 'o3d_base', + 'FColladaU', + 'google_nacl_imc', + 'technique', + 'antlr3c', + 'gtest', + 'skia' + ] + env['ICU_LIBS'], +) + +# Next, append renderer specific libraries to the linker environment +env.Append( + CPPPATH = env['RENDERER_INCLUDE_PATH'], + LIBPATH = [ + '$CG_DIR/lib', + ] + env['RENDERER_LIB_PATH'], + LIBS = env['RENDERER_LIBS'], +) + +run_env = env.Clone() +if env.Bit('linux'): + run_env.Append(ENV = os.environ) + run_env.Append( + ENV = {'LD_LIBRARY_PATH': run_env.Dir('$ARTIFACTS_DIR').abspath} + ) + +run_env.Append( + ENV = {'MOZ_PLUGIN_PATH': run_env.Dir('$ARTIFACTS_DIR').abspath, + 'MOZ_CRASHREPORTER_DISABLE': '1'}, + PYTHONPATH = ['$GFLAGS_DIR/python', + '$SELENIUM_PYTHON_DIR'] +) + +# Install runtime files required for the build type. +gl_requirements = [] +if env.Bit('windows'): + # The install step for these lives in import/build.scons. the + # import library always needs the Cg DLLs and executable, even on + # D3D. + gl_requirements += [ + '$ARTIFACTS_DIR/cg.dll', + '$ARTIFACTS_DIR/cgGL.dll', + '$ARTIFACTS_DIR/glew32.dll', + ] + +# TODO: shouldn't need this. +# Adding extra line for cleaner formatting. +env.Help('\n') + +# ------------------------------------------------------------------------- +# Unit tests + +# The basic unit tests +tests = [ + 'base/cross/bits_test.cc', + 'compiler/technique/technique_parser_test.cc', + 'core/cross/bitmap_test.cc', + 'core/cross/bounding_box_test.cc', + 'core/cross/buffer_test.cc', + 'core/cross/class_manager_test.cc', + 'core/cross/client_test.cc', + 'core/cross/counter_test.cc', + 'core/cross/curve_test.cc', + 'core/cross/draw_element_test.cc', + 'core/cross/draw_list_test.cc', + 'core/cross/draw_pass_test.cc', + 'core/cross/effect_test.cc', + 'core/cross/element_test.cc', + 'core/cross/fake_vertex_source.cc', + 'core/cross/features_test.cc', + 'core/cross/field_test.cc', + 'core/cross/float_n_test.cc', + 'core/cross/function_test.cc', + 'core/cross/material_test.cc', + 'core/cross/math_utilities_test.cc', + 'core/cross/matrix4_axis_rotation_test.cc', + 'core/cross/matrix4_composition_test.cc', + 'core/cross/matrix4_scale_test.cc', + 'core/cross/matrix4_translation_test.cc', +# Test disabled, pending investigation into NaCl API. +# 'core/cross/message_queue_test.cc', + 'core/cross/object_base_test.cc', + 'core/cross/pack_test.cc', + 'core/cross/param_array_test.cc', + 'core/cross/param_object_test.cc', + 'core/cross/param_operation_test.cc', + 'core/cross/param_test.cc', + 'core/cross/performance_timer_test.cc', + 'core/cross/primitive_test.cc', + 'core/cross/ray_intersection_info_test.cc', + 'core/cross/render_node_test.cc', + 'core/cross/renderer_test.cc', + 'core/cross/service_locator_test.cc', + 'core/cross/shape_test.cc', + 'core/cross/skin_test.cc', + 'core/cross/smart_ptr_test.cc', + 'core/cross/state_set_test.cc', + 'core/cross/state_test.cc', + 'core/cross/stream_bank_test.cc', + 'core/cross/stream_test.cc', + 'core/cross/transform_test.cc', + 'core/cross/tree_traversal_test.cc', + 'core/cross/vector_map_test.cc', + 'core/cross/vertex_source_test.cc', + 'core/cross/visitor_base_test.cc', + 'core/cross/weak_ptr_test.cc', + 'import/cross/gz_compressor_test.cc', + 'import/cross/gz_decompressor_test.cc', + 'import/cross/memory_buffer_test.cc', + 'import/cross/memory_stream_test.cc', + 'import/cross/raw_data_test.cc', + 'import/cross/tar_generator_test.cc', + 'import/cross/tar_processor_test.cc', + 'import/cross/targz_generator_test.cc', + 'import/cross/targz_processor_test.cc', + 'serializer/cross/serializer_test.cc', + 'tests/common/cross/test_utils.cc', + 'utils/cross/file_path_utils_test.cc', + 'utils/cross/file_text_reader_test.cc', + 'utils/cross/json_writer_test.cc', + 'utils/cross/string_reader_test.cc', + 'utils/cross/string_writer_test.cc', + 'utils/cross/temporary_file_test.cc', +] + +if env['TARGET_PLATFORM']=='WINDOWS': + tests += [ + # These are temporarily just being run for windows but should be + # moved to global when logging is working for the mac. + 'plugin/cross/plugin_logging_test.cc', + 'statsreport/aggregator-win32_unittest.cc', + 'statsreport/aggregator_unittest.cc', + 'statsreport/formatter_unittest.cc', + 'statsreport/metrics_unittest.cc', + 'statsreport/persistent_iterator-win32_unittest.cc', + 'breakpad/win/bluescreen_detector_test.cc', + ] + env.Append( + LINKFLAGS=['/SUBSYSTEM:WINDOWS'], + LIBS=[ + 'o3dStatsreport_Common', + 'o3dStatsreport', + 'o3dPlugin_logging', + 'o3dBreakpad', + 'shlwapi', + ] + ) + +# add command buffer renderer unit tests only on that renderer platform. +if 'RENDERER_CB' in env['CPPDEFINES']: + tests += [ + 'command_buffer/client/cross/id_allocator_test.cc', + 'command_buffer/common/cross/bitfield_helpers_test.cc', + 'command_buffer/service/cross/effect_utils_test.cc', + 'command_buffer/service/cross/resource_test.cc', + ] + if use_gmock: + tests += [ + 'command_buffer/client/cross/cmd_buffer_helper_test.cc', + 'command_buffer/client/cross/fenced_allocator_test.cc', + 'command_buffer/client/cross/buffer_sync_proxy_test.cc', + 'command_buffer/service/cross/buffer_rpc_test.cc', + 'command_buffer/service/cross/cmd_buffer_engine_test.cc', + 'command_buffer/service/cross/cmd_parser_test.cc', + ] + +unit_tests = env.Program('unit_tests', tests) + +# After building the test executable, force the windows executable to output +# stdout to a console window +# TODO: if WinMain/main is handled differently this isn't needed. +if env['TARGET_PLATFORM'] == 'WINDOWS': + blessed = env.AddPostAction(unit_tests, 'editbin /SUBSYSTEM:CONSOLE $TARGET') +else: + blessed = unit_tests + +# Install to artifacts. +unit_tests_install = env.Replicate('$ARTIFACTS_DIR', blessed) + +# Install any data required by the basic unit-tests +unit_tests_req = [] + +env['TEST_DATA_DIR'] = '$SCONSTRUCT_DIR/import/test_data' +unit_tests_req += env.Replicate( + '$ARTIFACTS_DIR/unittest_data', + [ + '$TEST_DATA_DIR/crate.dae', + '$TEST_DATA_DIR/crate.jpg', + '$TEST_DATA_DIR/rock01.tga', + '$TEST_DATA_DIR/rock02.tga', + ]) + +env['TECHNIQUE_TEST_DATA_DIR'] = '$SCONSTRUCT_DIR/compiler/technique/test_data' +unit_tests_req += env.Replicate( + '$ARTIFACTS_DIR/unittest_data', + [ + '$TECHNIQUE_TEST_DATA_DIR/fur.fx', + '$TECHNIQUE_TEST_DATA_DIR/lambert.fx', + '$TECHNIQUE_TEST_DATA_DIR/noshader.fx', + '$TECHNIQUE_TEST_DATA_DIR/notechnique.fx', + '$TECHNIQUE_TEST_DATA_DIR/sampler_test.fx', + '$TECHNIQUE_TEST_DATA_DIR/shadow_map.fx', + '$TECHNIQUE_TEST_DATA_DIR/simple.fx', + ]) + +unit_tests_req += env.Replicate( + '$ARTIFACTS_DIR/bitmap_test', + '$SCONSTRUCT_DIR/tests/bitmap_test/*') + +unit_tests_req += env.Replicate( + '$ARTIFACTS_DIR/archive_files', + '$SCONSTRUCT_DIR/tests/archive_files/*') + +# Also require gl related libraries based on variant. +unit_tests_req += gl_requirements + +# Add requirements for unit tests. +env.Requires(unit_tests_install, unit_tests_req) + +# TODO: temporarily continue to use aliases to run tests. +# This need to eventually switch to use ComponentTestProgram once +# other sections have been adjusted. +env['PROGRAM_NAME'] = unit_tests_install[0].path +env['PROGRAM_BASENAME'] = os.path.join('$ARTIFACTS_DIR', 'unit_tests') +env.AlwaysBuild(run_env.Alias('unit_tests', unit_tests_install, + env.subst('$COMPONENT_TEST_CMDLINE'))) + +# Add help. +env.Help('unit_tests: run unit tests\n') + +if env.Bit('mac'): + env['SHLINKFLAGS'] = ['-F$CG_DIR'] + env['SHLIBPREFIX'] = [''] + env['SHLIBSUFFIX'] = [''] + + env.Append( + FRAMEWORKS = [ + 'AGL', + 'Accelerate', + 'AudioToolbox', + 'AudioUnit', + 'Carbon', + 'Cg', + 'CoreAudio', + 'Foundation', + 'GLUT', + 'OpenAL', + 'OpenGL', + ], + CCFLAGS = ['-F$CG_DIR'], + LINKFLAGS = ['-F$CG_DIR'], + SHLINKFLAGS = ['-F$CG_DIR'] + ) + + env.AddPostAction( + unit_tests_install, + [ + # Change install name reference + # make Cg.framework point to copy in $THIRD_PARTY + '/usr/bin/install_name_tool ' + '-change @executable_path/../Library/Frameworks/Cg.framework/Cg ' + '"$CG_DIR/Cg.framework/Cg" ' + '"$ARTIFACTS_DIR/unit_tests"' + ]) + + +#---------------------------------------------------------------------------- +# Install the perceptual diff tool and its requirements. + +installed_pdiff = None +pdiff = None +pdiff_requirements = [] +if env.Bit('windows'): + # Install the perceptual-diff utility for lossy image comparisons + pdiff = '$PDIFF_DIR/bin/win/perceptualdiff.exe' + # perceptualdiff.exe also needs FreeImage.dll to run + pdiff_requirements = env.Replicate('$ARTIFACTS_DIR', + '$PDIFF_DIR/bin/win/FreeImage.dll') +elif env.Bit("linux"): + pdiff = '$PDIFF_DIR/bin/linux/perceptualdiff' +elif env.Bit("mac"): + pdiff = '$PDIFF_DIR/bin/mac/perceptualdiff' + +if pdiff: + installed_pdiff = env.Replicate('$ARTIFACTS_DIR', pdiff) + run_env["PDIFF_PATH"] = installed_pdiff[0] + env.Requires(installed_pdiff, pdiff_requirements) + +# ------------------------------------------------------------------------- +# System tests + +# Only define and run the system tests if they are enabled. +if ARGUMENTS.get('SYSTEM_TESTS_ENABLED', False): + # Build the system tests + system_testprog = env.Program('system_tests', + 'basic_system_test/basic_system_test.cc') + + # After building the test executable, force the windows executable to output + # stdout to a console window + if env.Bit('windows'): + blessed = env.AddPostAction(system_testprog, + 'editbin /SUBSYSTEM:CONSOLE $TARGET') + else: + blessed = system_testprog + system_tests_install = env.Replicate('$ARTIFACTS_DIR', blessed) + + # Gather requirements for system tests. + system_tests_req = [] + + # TODO : The system tests are currently limited to Direct3D. + if env.Bit('windows') and 'RENDERER_D3D9' in env['CPPDEFINES']: + system_tests_req += env.Replicate( + '$ARTIFACTS_DIR', + ['test_driver.bat', 'test_driver.py']) + + # Install the assets required for the basic system test. + system_tests_req += env.Replicate( + '$ARTIFACTS_DIR/basic_system_test/reference_frames', + 'basic_system_test/reference_frames/*') + system_tests_req += env.Replicate( + '$ARTIFACTS_DIR/basic_system_test', + 'basic_system_test/reference_stream.csv') + + # Copy the PIX utility and experiment file to the testing build directory. + if env.Bit('windows') and 'RENDERER_D3D9' in env['CPPDEFINES']: + # Replicate a script which will package all of the files required, + # for D3D9-tests. + pix_requirements = env.Replicate( + '$ARTIFACTS_DIR', + [ + '$DIRECTX9_DIR/utilities/bin/x86/PIXWin.exe', + '$DIRECTX9_DIR/utilities/bin/x86/PIXHelper.dll', + '$DIRECTX9_DIR/utilities/bin/x86/PIXAdmin.exe', + '$DIRECTX9_DIR/utilities/bin/x86/Detoured.dll', + '$DIRECTX9_DIR/runtime/x86/d3dref9.dll', + 'testing_framework_reference.PIXExp', + 'testing_framework_hardware.PIXExp', + 'package_tests.bat', + ]) + system_tests_req += pix_requirements + + if installed_pdiff: + system_tests_req += installed_pdiff + + # Also require gl related libraries based on variant. + system_tests_req += gl_requirements + + # Add requirements for system_tests. + env.Requires(system_tests_install, system_tests_req) + + # Get command line flags for tests driver. + if int(ARGUMENTS.get('hardware', 1)): + env.Replace(TEST_DRIVER_FLAGS = '-hardware') + + # Create an alias for the execution of the system tests. + env.Alias('system_tests') + # Only add actual step if d3d mode (for now). + if 'RENDERER_D3D9' in env['CPPDEFINES']: + if env.get('COVERAGE_ENABLED'): + # TODO: temporarily continue to use aliases to run tests. + # This need to eventually switch to use ComponentTestProgram once + # other sections have been adjusted. + # When running coverage, don't run system_tests thru test_driver.py + env['PROGRAM_NAME'] = system_tests_install[0].path + env['PROGRAM_BASENAME'] = os.path.join('$ARTIFACTS_DIR', 'system_tests') + env.AlwaysBuild(run_env.Alias( + 'system_tests', system_tests_install, + env.subst('$COMPONENT_TEST_CMDLINE'))) + else: + env.AlwaysBuild(run_env.Alias( + 'system_tests', system_tests_install, + 'cd $ARTIFACTS_DIR && ' + \ + sys.executable + ' $ARTIFACTS_DIR/test_driver.py $TEST_DRIVER_FLAGS')) + # Add help. + env.Help('system_tests: run system tests\n') + + +#---------------------------------------------------------------------------- +# Selenium Tests + +run_env.Replace( + SELENIUM_VERBOSE = ARGUMENTS.get('SELENIUM_VERBOSE', '0'), + SELENIUM_SERVER_JAR = '$SELENIUM_JAVA_DIR/server/selenium-server.jar', + SELENIUM_TEST_PREFIX = ARGUMENTS.get('SELENIUM_TEST_PREFIX', 'Test'), + SELENIUM_TEST_SUFFIXES = ARGUMENTS.get('SELENIUM_TEST_SUFFIXES', + 'small,medium,large'), + SELENIUM_CAPTURE_SCREENSHOTS = ARGUMENTS.get( + 'SELENIUM_CAPTURE_SCREENSHOTS', + ''), + SELENIUM_FLAGS = ('--verbose=$SELENIUM_VERBOSE ' + '--selenium_server="$SELENIUM_SERVER_JAR" ' + '--testprefix=$SELENIUM_TEST_PREFIX ' + '--testsuffixes=$SELENIUM_TEST_SUFFIXES ' + '--screencompare=$PDIFF_PATH ' + '$SELENIUM_CAPTURE_SCREENSHOTS ' + '$SELENIUM_EXTRA_FLAGS'), +) + +if run_env.Bit('windows'): + from SCons.Platform.win32 import get_program_files_dir + path_contents = '%s/Mozilla Firefox;%s' % ( + get_program_files_dir(), + run_env.Dir('$ARTIFACTS_DIR').abspath) + run_env.Append( + ENV = {'PATH': '%s/Mozilla Firefox;%s' % ( + get_program_files_dir(), + run_env.Dir('$ARTIFACTS_DIR').abspath)}, + ) + run_env.Append( + ENV = {'USERPROFILE': os.environ['USERPROFILE']} + ) + +# The Macintosh Firefox apparently does not support the MOZ_PLUGIN_PATH. +# On the Mac we can run a hermetic version of Firefox and allow it to find +# the O3D plugin by adding a symlink to it inside the plugins directory +# inside the Firefox.app bundle. We then instruct selenium to run this +# specific version of Firefox. All of this avoids having to install +# the plugin in a system directory which could be bad on +# auto-build machines, etc. +plugin_path = '$ARTIFACTS_DIR/${LIBPREFIX}npo3dautoplugin$SHLIBSUFFIX' +browser_path = '' +plugin_install_steps = [] +cleanup_steps = [] +if run_env.Bit('mac'): + plugin_path = '$ARTIFACTS_DIR/O3D.plugin' + if run_env['MAC_HERMETIC_FIREFOX_DIR']: + run_env['MAC_FIREFOX_DIR'] = '$MAC_HERMETIC_FIREFOX_DIR' + run_env['MAC_FIREFOX_APP'] = '$MAC_FIREFOX_DIR/Firefox.app' + run_env['MAC_FIREFOX_TGZ'] = '$MAC_FIREFOX_DIR/firefox.tgz' + browser_path = '$MAC_FIREFOX_APP/Contents/MacOS/firefox-bin' + plugin_install_steps = [ + 'rm -rf "$MAC_FIREFOX_APP"', + 'cd $MAC_FIREFOX_DIR && tar xfz "$MAC_FIREFOX_TGZ"', + 'ln -fs "' + plugin_path + '" "$MAC_FIREFOX_APP/Contents/MacOS/plugins"', + ] + cleanup_steps = [ + 'rm -rf "$MAC_FIREFOX_APP"', + ] + +def DeferSelenium(env): + run_selenium_firefox = run_env.Alias( + 'selenium_firefox', + [plugin_path, env.GetPublished('samples', 'asset_files')], + # TODO: have a cleaner way to do this. + [Delete('$ARTIFACTS_DIR/selenium/screenshots_firefox'), + Mkdir('$ARTIFACTS_DIR/selenium/screenshots_firefox')] + + plugin_install_steps + + [run_env.Python([ + 'tests/selenium/main.py', + '$SELENIUM_FLAGS', + '--browser=*firefox', + '--browserpath="' + browser_path + '"', + '--referencedir=$TEST_REFERENCE_IMAGES', + '--screenshotsdir=$ARTIFACTS_DIR/selenium/screenshots_firefox'])] + + cleanup_steps, + ) + + if run_env.Bit('windows'): + run_selenium_ie = run_env.Alias( + 'selenium_ie', + ['$ARTIFACTS_DIR/${LIBPREFIX}npo3dautoplugin$SHLIBSUFFIX', + env.GetPublished('samples', 'asset_files')], + # TODO: have a cleaner way to do this. + [Delete('$ARTIFACTS_DIR/selenium/screenshots_ie'), + Mkdir('$ARTIFACTS_DIR/selenium/screenshots_ie'), + run_env.Python([ + 'tests/selenium/main.py', + '$SELENIUM_FLAGS', + '--browser=*iexplore', + '--servertimeout=80', + '--referencedir=$TEST_REFERENCE_IMAGES', + '--screenshotsdir=$ARTIFACTS_DIR/selenium/screenshots_ie'])], + ) + run_env.Requires(run_selenium_ie, '$IE_PLUGIN_DIR') + + run_selenium_chrome = run_env.Alias( + 'selenium_chrome', + ['$ARTIFACTS_DIR/${LIBPREFIX}npo3dautoplugin$SHLIBSUFFIX', + env.GetPublished('samples', 'asset_files')], + # TODO: have a cleaner way to do this. + [Delete('$ARTIFACTS_DIR/selenium/screenshots_chrome'), + Mkdir('$ARTIFACTS_DIR/selenium/screenshots_chrome'), + run_env.Python([ + 'tests/selenium/main.py', + '$SELENIUM_FLAGS', + '--browser=*googlechrome', + '--referencedir=$TEST_REFERENCE_IMAGES', + '--screenshotsdir=$ARTIFACTS_DIR/selenium/screenshots_chrome'])], + ) + # Chrome requires that the plug-in be located in the install path. + env.Requires(run_selenium_chrome, env.Alias('install')) + + if installed_pdiff: + env.Requires(run_selenium_firefox, installed_pdiff) + if run_env.Bit('windows'): + env.Requires(run_selenium_ie, installed_pdiff) + env.Requires(run_selenium_chrome, installed_pdiff) + + env.AlwaysBuild(run_selenium_firefox) + if run_env.Bit('windows'): + env.AlwaysBuild(run_selenium_ie) + env.AlwaysBuild(run_selenium_chrome) + + run_env.Alias('selenium', run_selenium_firefox) + +run_env.Defer(DeferSelenium) + +# Add help. +env.Help('selenium_{firefox|ie|chrome): run selenium tests in the given browser\n') + + +# Add generation of lump for hive selenium tests. +if env.AnyBits('mac', 'windows'): + selenium_env = env.Clone() + selenium_env.AppendENVPath('PATH', + os.environ.get('PRESCONS_PATH', '').split(';')) + + # Pull in all pulse related environment variables. + for k in os.environ: + if k.startswith('PULSE_'): + selenium_env['ENV'][k] = os.environ[k] + + selenium_env['PREP_SELENIUM_ARCHIVE'] = ( + '$TARGET_ROOT/${PREP_SELENIUM_ARCHIVE_NAME}.zip') + + if int(ARGUMENTS.get('O3D_ENABLE_BREAKPAD', 0)): + selenium_env['O3D_BRANCH'] = 'release' + else: + selenium_env['O3D_BRANCH'] = 'trunk' + + if env.Bit('mac'): + selenium_env['PREP_SELENIUM_ARCHIVE_NAME'] = 'O3Dtests_mac' + selenium_env['GNU_SETUP_EXTRAS'] = '' + selenium_env['SETUP_SCRIPTS'] = ( + 'export PYTHONPATH=' + env.Dir('$MAIN_DIR/scripts').abspath) + else: + selenium_env['PREP_SELENIUM_ARCHIVE_NAME'] = 'O3Dtests' + selenium_env['GNU_SETUP_EXTRAS'] = r'..\third_party\gnu\setup_env.bat && ' + selenium_env['SETUP_SCRIPTS'] = ( + 'set PYTHONPATH=' + env.Dir('$MAIN_DIR/scripts').abspath) + + selenium_env.AlwaysBuild(selenium_env.Alias('prep_selenium', [], + [Delete('$TARGET_ROOT/${PREP_SELENIUM_ARCHIVE_NAME}'), + '$SETUP_SCRIPTS && ' + 'cd tests && cd lab_automation && ' + + sys.executable + ' prepare_selenium_tests.py ' + '$TARGET_ROOT/${PREP_SELENIUM_ARCHIVE_NAME}', + Delete('$PREP_SELENIUM_ARCHIVE'), + '${GNU_SETUP_EXTRAS}' + 'cd $TARGET_ROOT && ' + 'zip -9 -r $PREP_SELENIUM_ARCHIVE ${PREP_SELENIUM_ARCHIVE_NAME}', + ])) + + + +#-------------------------------------------------------------------------- +# General stuff + +presubmit_tests = [ + env.Alias('unit_tests'), +] + +if ARGUMENTS.get('SYSTEM_TESTS_ENABLED', False): + presubmit_tests += [ + env.Alias('system_tests'), + ] + +# TODO: Make presubmit run selenium once the OpenGL build is +# completely working. +if 'RENDERER_D3D9' in env['CPPDEFINES']: + presubmit_tests += [ + env.Alias('selenium_firefox'), + ] + +env.Alias('presubmit', presubmit_tests) +env.Help('presubmit: run unit tests and selenium integration tests.\n') + +# Add an alias for what to run on Pulse. +pulse_tests = [env.Alias('presubmit')] +# OpenGL tests don't work with selenium yet. +if 'RENDERER_D3D9' in env['CPPDEFINES']: + pulse_tests += [env.Alias('selenium_firefox'), + env.Alias('selenium_ie')] +# Add selenium for mac. +if env.Bit('mac'): + pulse_tests += [env.Alias('selenium')] + +env.Alias('pulse_tests', pulse_tests) +env.Help('pulse_tests: the test target that automatic builds use.\n') + +# TODO: shouldn't need this. +# Adding extra line for cleaner formatting. +env.Help('\n') + + +#-------------------------------------------------------------------------- +# Other odds and ends + +# Install presubmit_tests batch file. +# TODO: is this really needed anymore? +env.Replicate('$ARTIFACTS_DIR', 'presubmit_tests.bat') diff --git a/o3d/tests/common/build.scons b/o3d/tests/common/build.scons new file mode 100644 index 0000000..8add24f --- /dev/null +++ b/o3d/tests/common/build.scons @@ -0,0 +1,55 @@ +# Copyright 2009, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +Import('env') + +env.Append(CPPPATH = ['$RENDERER_INCLUDE_PATH']) + +inputs = [ + "cross/main.cc", +] + +if env.Bit('windows'): + inputs += [ + "win/dxcapture.cc", + "win/testing_common.cc", + ] + +if env.Bit('linux'): + inputs += [ + "linux/testing_common.cc", + ] + +if env.Bit('mac'): + inputs += [ + "mac/testing_common.cc", + ] + +o3dcore_lib = env.ComponentLibrary("testing_common", inputs) diff --git a/o3d/tests/common/cross/main.cc b/o3d/tests/common/cross/main.cc new file mode 100644 index 0000000..b4bdbd2 --- /dev/null +++ b/o3d/tests/common/cross/main.cc @@ -0,0 +1,45 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// defines the common main() for all unit tests +#include <build/build_config.h> +#include "gtest/gtest.h" + +#ifdef OS_WIN +int test_main(int argc, wchar_t **argv) { +#else +int test_main(int argc, char **argv) { +#endif + testing::InitGoogleTest(&argc, argv); + + return RUN_ALL_TESTS(); +} diff --git a/o3d/tests/common/cross/test_utils.cc b/o3d/tests/common/cross/test_utils.cc new file mode 100644 index 0000000..d34b28f --- /dev/null +++ b/o3d/tests/common/cross/test_utils.cc @@ -0,0 +1,68 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// useful utility functions for unit/functional testing + +#include "tests/common/cross/test_utils.h" +#include <sys/stat.h> +#include "core/cross/client.h" +#include "import/cross/targz_processor.h" +#include "tests/common/win/testing_common.h" + +namespace test_utils { + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +uint8 *ReadFile(o3d::String file, size_t *data_size) { + FILE *fp = fopen(file.c_str(), "rb"); + + if (fp == NULL) return NULL; + + // Figure out the file length + struct stat file_info; + stat(file.c_str(), &file_info); + size_t file_size = file_info.st_size; + + // Read it all into memory + // TODO: this should be new[] instead of malloc. + uint8 *data = static_cast<uint8*>(malloc(file_size)); + DCHECK(data); + + int bytes_read = fread(data, 1, file_size, fp); + fclose(fp); + DCHECK_EQ(bytes_read, file_size); + + // Return file size and data + if (data_size) *data_size = file_size; + return data; +} + +} // namespace test_utils diff --git a/o3d/tests/common/cross/test_utils.h b/o3d/tests/common/cross/test_utils.h new file mode 100644 index 0000000..1d3c54f --- /dev/null +++ b/o3d/tests/common/cross/test_utils.h @@ -0,0 +1,51 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// useful utility functions for unit/functional testing + +#ifndef O3D_TESTS_COMMON_CROSS_TEST_UTILS_H_ +#define O3D_TESTS_COMMON_CROSS_TEST_UTILS_H_ + +#include "core/cross/client.h" +#include "tests/common/win/testing_common.h" + +namespace test_utils { + +// Reads the given file into memory and returns a pointer +// to its contents. The file size is returned in |data_size| +// The caller is responsible for calling free() +// NULL is returned if there's an error +uint8 *ReadFile(o3d::String file, size_t *data_size); + +} // namespace test_utils + +#endif // O3D_TESTS_COMMON_CROSS_TEST_UTILS_H_ diff --git a/o3d/tests/common/linux/testing_common.cc b/o3d/tests/common/linux/testing_common.cc new file mode 100644 index 0000000..318b278 --- /dev/null +++ b/o3d/tests/common/linux/testing_common.cc @@ -0,0 +1,169 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// Contains windows-specific code for setting up the Client object +// used in the unit tests. Defines WinMain and a WindowProc for running +// the GUnit tests + +#include "core/cross/class_manager.h" +#include "core/cross/evaluation_counter.h" +#include "core/cross/install_check.h" +#include "core/cross/features.h" +#include "core/cross/object_manager.h" +#include "core/cross/profiler.h" +#include "core/cross/renderer.h" +#include "core/cross/renderer_platform.h" +#include "core/cross/service_locator.h" +#include "core/cross/types.h" + +o3d::String *g_program_path = NULL; +o3d::String *g_program_name = NULL; +o3d::Renderer* g_renderer = NULL; +o3d::ServiceLocator* g_service_locator = NULL; +o3d::DisplayWindow* g_display_window = NULL; + +Display *g_display = NULL; +Window g_window = 0; + +static char kOffScreenRenderer[] = "O3D_D3D9_OFF_SCREEN"; + +extern int test_main(int argc, char **argv); + +int main(int argc, char *argv[]) { + std::string error; + if (!o3d::RendererInstallCheck(&error)) { + return false; + } + + std::string program_path(argv[0]); + std::string program_name; + + // Remove all characters starting with last '/'. + size_t backslash_pos = program_path.rfind('/'); + if (backslash_pos != o3d::String::npos) { + program_name = program_path.substr(backslash_pos + 1); + if (backslash_pos == 0) { + program_path = "/"; + } else { + program_path.erase(backslash_pos); + } + } else { + program_name = program_path; + program_path = "."; + } + + g_program_path = &program_path; + g_program_name = &program_name; + + o3d::ServiceLocator service_locator; + g_service_locator = &service_locator; + + o3d::EvaluationCounter evaluation_counter(g_service_locator); + o3d::ClassManager class_manager(g_service_locator); + o3d::ObjectManager object_manager(g_service_locator); + o3d::Profiler profiler(g_service_locator); + o3d::Features features(g_service_locator); + + // create a renderer device based on the current platform + g_renderer = o3d::Renderer::CreateDefaultRenderer(g_service_locator); + + g_display = ::XOpenDisplay(0); + int attribs[] = { + GLX_RGBA, + GLX_DOUBLEBUFFER, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + None + }; + XVisualInfo *visualInfo = ::glXChooseVisual(g_display, + DefaultScreen(g_display), + attribs); + Window root_window = RootWindow(g_display, visualInfo->screen); + Colormap colorMap = ::XCreateColormap(g_display, + root_window, + visualInfo->visual, + AllocNone); + + XSetWindowAttributes windowAttributes; + windowAttributes.colormap = colorMap; + windowAttributes.border_pixel = 0; + windowAttributes.event_mask = StructureNotifyMask; + g_window = ::XCreateWindow(g_display, + root_window, + 0, 0, 800, 600, + 0, + visualInfo->depth, + InputOutput, + visualInfo->visual, + CWBorderPixel|CWColormap|CWEventMask, + &windowAttributes); + ::XFree(visualInfo); + ::XMapWindow(g_display, g_window); + ::XSync(g_display, True); + + o3d::DisplayWindowLinux* display_window = + new o3d::DisplayWindowLinux(); + display_window->set_display(g_display); + display_window->set_window(g_window); + g_display_window = display_window; + + // Initialize the renderer for off-screen rendering if kOffScreenRenderer + // is in the environment. + bool success; + if (getenv(kOffScreenRenderer)) { + success = + g_renderer->Init(*g_display_window, true) == o3d::Renderer::SUCCESS; + } else { + success = + g_renderer->Init(*g_display_window, false) == o3d::Renderer::SUCCESS; + } + + int ret = EXIT_FAILURE; + if (!success) { + ::fprintf(stdout, "Failed to initialize renderer\n"); + } else { + ret = test_main(argc, argv); + } + + g_renderer->Destroy(); + delete g_renderer; + g_renderer = NULL; + + delete display_window; + g_display_window = NULL; + g_program_path = NULL; + g_program_name = NULL; + ::XCloseDisplay(g_display); + + return ret; +} diff --git a/o3d/tests/common/mac/testing_common.cc b/o3d/tests/common/mac/testing_common.cc new file mode 100644 index 0000000..e102fc8 --- /dev/null +++ b/o3d/tests/common/mac/testing_common.cc @@ -0,0 +1,134 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// Contains macintosh-specific code for setting up the Client object +// used in the unit tests. + +#include <OpenGL/OpenGL.h> +#include <OpenGL/gl.h> +#include <OpenGL/glu.h> +#include <GLUT/glut.h> +#include <AGL/agl.h> + +#include "core/cross/class_manager.h" +#include "core/cross/evaluation_counter.h" +#include "core/cross/install_check.h" +#include "core/cross/features.h" +#include "core/cross/object_manager.h" +#include "core/cross/profiler.h" +#include "core/cross/renderer.h" +#include "core/cross/renderer_platform.h" +#include "core/cross/service_locator.h" +#include "core/cross/types.h" + +o3d::String *g_program_path = NULL; +o3d::String *g_program_name = NULL; +o3d::Renderer* g_renderer = NULL; +o3d::ServiceLocator* g_service_locator = NULL; +o3d::DisplayWindow* g_display_window = NULL; + +const unsigned int kWindowWidth = 800; +const unsigned int kWindowHeight = 600; + +extern int test_main(int argc, char **argv); + +int main(int argc, char *argv[]) { + std::string error; + if (!o3d::RendererInstallCheck(&error)) { + return false; + } + + std::string program_path(argv[0]); + std::string program_name; + + // Remove all characters starting with last '/'. + size_t backslash_pos = program_path.rfind('/'); + if (backslash_pos != o3d::String::npos) { + program_name = program_path.substr(backslash_pos + 1); + if (backslash_pos == 0) { + program_path = "/"; + } else { + program_path.erase(backslash_pos); + } + } else { + program_name = program_path; + program_path = "."; + } + + g_program_path = &program_path; + g_program_name = &program_name; + + o3d::ServiceLocator service_locator; + g_service_locator = &service_locator; + + o3d::EvaluationCounter evaluation_counter(g_service_locator); + o3d::ClassManager class_manager(g_service_locator); + o3d::ObjectManager object_manager(g_service_locator); + o3d::Profiler profiler(g_service_locator); + o3d::Features features(g_service_locator); + + // create a renderer device based on the current platform + g_renderer = o3d::Renderer::CreateDefaultRenderer(g_service_locator); + + glutInit(&argc, argv); + glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH | GLUT_STENCIL); + glutInitWindowSize(kWindowWidth, kWindowHeight); + glutInitWindowPosition(100, 100); + glutCreateWindow(argv[0]); + + // Give the renderer the CGL context + CGLContextObj cgl_context = CGLGetCurrentContext(); + o3d::DisplayWindowMac* display_window = new o3d::DisplayWindowMac(); + g_display_window = display_window; + display_window->set_agl_context(NULL); + display_window->set_cgl_context(cgl_context); + bool success = g_renderer->Init(*g_display_window, + false) == o3d::Renderer::SUCCESS; + + int ret = EXIT_FAILURE; + if (!success) { + ::fprintf(stdout, "Failed to initialize renderer\n"); + } else { + ret = test_main(argc, argv); + } + + g_renderer->Destroy(); + delete g_renderer; + g_renderer = NULL; + + delete display_window; + g_display_window = NULL; + g_program_path = NULL; + g_program_name = NULL; + + return ret; +} diff --git a/o3d/tests/common/win/dxcapture.cc b/o3d/tests/common/win/dxcapture.cc new file mode 100644 index 0000000..0afb91b --- /dev/null +++ b/o3d/tests/common/win/dxcapture.cc @@ -0,0 +1,140 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// File containing implementation routines for the DirectX testing framework +// framebuffer and command stream capture routines. + +#include "tests/common/win/dxcapture.h" + +#include <d3dx9.h> + +#include "core/cross/types.h" +#include "core/win/d3d9/d3d_entry_points.h" +#include "core/win/d3d9/renderer_d3d9.h" +#include "core/win/d3d9/utils_d3d9.h" +#include "tests/common/win/testing_common.h" + +namespace directx_capture { + +void StartCommandCapture(const wchar_t* stream_name) { +#if defined(RENDERER_D3D9) + if (D3DPERF_GetStatus()) { + D3DPERF_SetMarker(0, stream_name); + D3DPERF_SetMarker(0, L"BeginCommandStreamCapture"); + } +#endif +} + +void EndCommandCapture() { +#if defined(RENDERER_D3D9) + if (D3DPERF_GetStatus()) { + D3DPERF_SetMarker(0, L"EndCommandStreamCapture"); + } +#endif +} + +void CaptureFramebuffer(const wchar_t* buffer_metadata) { +#if defined(RENDERER_D3D9) + // Keep track of the invocation count for output file-naming purposes. + static int g_call_count = 0; + ++g_call_count; + + // If PIX is present, then send a message to PIX requesting a framebuffer + // capture. + if (D3DPERF_GetStatus()) { + ::Sleep(500); + D3DPERF_SetMarker(0, buffer_metadata); + D3DPERF_SetMarker(0, L"CaptureScreenContents"); + } else { + // Otherwise, explicitly read the contents of the buffer into system memory + // and story a .png file. + o3d::RendererD3D9* d3d9_renderer = + down_cast<o3d::RendererD3D9*>(g_renderer); + LPDIRECT3DDEVICE9 device = d3d9_renderer->d3d_device(); + IDirect3DSurface9* system_surface = NULL; + IDirect3DSurface9* current_surface = NULL; + + HR(device->GetRenderTarget(0, ¤t_surface)); + D3DSURFACE_DESC surface_description; + HR(current_surface->GetDesc(&surface_description)); + + // Construct an intermediate surface with multi-sampling disabled. + // This surface is required because GetRenderTargetData(...) will fail + // for multi-sampled targets. One must first down-sample to a + // non-multi-sample buffer, and then copy from that intermediate buffer + // to a main memory surface. + IDirect3DSurface9* intermediate_target; + HR(device->CreateRenderTarget(surface_description.Width, + surface_description.Height, + surface_description.Format, + D3DMULTISAMPLE_NONE, + 0, + FALSE, + &intermediate_target, + NULL)); + + HR(device->StretchRect(current_surface, + NULL, + intermediate_target, + NULL, + D3DTEXF_NONE)); + + HR(device->CreateOffscreenPlainSurface(surface_description.Width, + surface_description.Height, + surface_description.Format, + D3DPOOL_SYSTEMMEM, + &system_surface, + NULL)); + + HR(device->GetRenderTargetData(intermediate_target, system_surface)); + + const o3d::String file_name(*g_program_name + + o3d::String("_") + + UintToString(g_call_count) + + o3d::String(".png")); + + std::wstring file_name_utf16 = UTF8ToWide(file_name); + + HR(o3d::D3DXSaveSurfaceToFile(file_name_utf16.c_str(), + D3DXIFF_PNG, + system_surface, + NULL, + NULL)); + + system_surface->Release(); + intermediate_target->Release(); + current_surface->Release(); + } +#endif +} + +} // end namespace directx_capture diff --git a/o3d/tests/common/win/dxcapture.h b/o3d/tests/common/win/dxcapture.h new file mode 100644 index 0000000..c62ce2c --- /dev/null +++ b/o3d/tests/common/win/dxcapture.h @@ -0,0 +1,68 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// File exposing a set functions to capture the direct-X command +// stream and frame-buffer contents. This class is to be used for +// regression-testing purposes. + +#ifndef O3D_TESTS_COMMON_WIN_DXCAPTURE_H__ +#define O3D_TESTS_COMMON_WIN_DXCAPTURE_H__ + +// Singleton class encapsulating functionality to capture DX command streams +// and framebuffer contents. +namespace directx_capture { + +// Routine to inform the testing framework that graphics command logs +// should be captured. The contents of stream_name will be embedded in the +// logs for ease of human readability. +// NOTE: Requires that the executable be invoked through PIX. Fn is a no-op +// when the PIX environment is not present. +void StartCommandCapture(const wchar_t* stream_name); + +// Invoke to disable stream capture. Note that the start/end routines +// are NOT re-entrant. One cannot nest stream captures. +// NOTE: Requires that the executable be invoked through PIX. Fn is a no-op +// when the PIX environment is not present. +void EndCommandCapture(); + +// Invoke to capture the current contents of the framebuffer. If stream +// capture is active, the contents of buffer_metadata will be written to the +// logs. +// NOTE: If PIX is present, then the frame-buffer is captured and stored by +// PIX according to the PIXRun file. Otherwise, the contents of the current +// render target surface are saved explicitly by the code. The meta-data +// is ignored when PIX is not present. +void CaptureFramebuffer(const wchar_t* buffer_metadata); + +} // end namespace directx_capture + +#endif // O3D_TESTS_COMMON_WIN_DXCAPTURE_H__ diff --git a/o3d/tests/common/win/system_test.h b/o3d/tests/common/win/system_test.h new file mode 100644 index 0000000..65e060c --- /dev/null +++ b/o3d/tests/common/win/system_test.h @@ -0,0 +1,82 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// File containing assert-macros for use in O3D rendering system-tests. + +#ifndef O3D_TESTS_COMMON_WIN_SYSTEM_TEST_H__ +#define O3D_TESTS_COMMON_WIN_SYSTEM_TEST_H__ + +#ifdef OS_WIN + +#include "tests/common/win/dxcapture.h" + +// A helper-macro to widen strings. +#define WIDEN_STRING2(x) L##x +#define WIDEN_STRING(x) WIDEN_STRING2(x) + +// Initiates capture of the DX command stream. The start of the captured +// stream will contain a message indicating the values of the line and +// file arguments. +inline void BeginStreamCapture(int line, const wchar_t* file) { + wchar_t debug_buffer[2048]; + _snwprintf_s(debug_buffer, 2048, L"Stream_Capture: %i : %s", line, file); + directx_capture::StartCommandCapture(debug_buffer); +} + +// Places a debug marker in the graphics command stream containing +// the values of line and file, and requests that the current framebuffer +// contents be captured. +inline void CaptureFrameBuffer(int line, const wchar_t* file) { + wchar_t debug_buffer[2048]; + _snwprintf_s(debug_buffer, 2048, L"Frame_Capture: %i : %s", line, file); + directx_capture::CaptureFramebuffer(debug_buffer); +} + +// Macros placing stream-capture begin-end waypoints in the testing application. +#define BEGIN_ASSERT_STREAM_CAPTURE() \ + BeginStreamCapture(__LINE__, WIDEN_STRING(__FILE__)) + +#define END_ASSERT_STREAM_CAPTURE() \ + directx_capture::EndCommandCapture() + +#define ASSERT_FRAMEBUFFER() \ + CaptureFrameBuffer(__LINE__, WIDEN_STRING(__FILE__)) + +#else + +#define BEGIN_ASSERT_STREAM_CAPTURE() do {} while (0) +#define END_ASSERT_STREAM_CAPTURE() do {} while (0) +#define ASSERT_FRAMEBUFFER() do {} while (0) + +#endif + +#endif // O3D_TESTS_COMMON_WIN_SYSTEM_TEST_H__ diff --git a/o3d/tests/common/win/testing_common.cc b/o3d/tests/common/win/testing_common.cc new file mode 100644 index 0000000..e51fc6a --- /dev/null +++ b/o3d/tests/common/win/testing_common.cc @@ -0,0 +1,202 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// Contains windows-specific code for setting up the Client object +// used in the unit tests. Defines WinMain and a WindowProc for running +// the GUnit tests + +#include <windows.h> +#include <Shellapi.h> +#include <d3dx9.h> + +#include "tests/common/win/testing_common.h" +#include "core/cross/install_check.h" +#include "core/cross/service_locator.h" +#include "core/cross/evaluation_counter.h" +#include "core/cross/class_manager.h" +#include "core/cross/features.h" +#include "core/cross/object_manager.h" +#include "core/cross/profiler.h" +#include "core/cross/renderer.h" +#include "core/cross/renderer_platform.h" +#include "core/cross/types.h" + +o3d::ServiceLocator* g_service_locator = NULL; +o3d::DisplayWindow* g_display_window = NULL; + +HWND g_window_handle = NULL; + +o3d::String *g_program_path = NULL; +o3d::String *g_program_name = NULL; +o3d::Renderer* g_renderer = NULL; + +static wchar_t kOffScreenRenderer[] = L"O3D_D3D9_OFF_SCREEN"; + +extern int test_main(int argc, wchar_t **argv); + +LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { + return true; +} + +// Handles some errors that would typically cause an OS dialog box to appear. +LONG WINAPI LocalUnhandledExceptionFilter(EXCEPTION_POINTERS* pep) { + fprintf(stdout, "ERROR: Unhandled Exception\n"); + exit(EXIT_FAILURE); +} + +// Main entry point for the app. Creates a new window, and calls main() +int WINAPI WinMain(HINSTANCE instance, + HINSTANCE prev_instance, + LPSTR cmd_line, + int n_cmd_show) { + // Turn off some of the OS error dialogs. + ::SetUnhandledExceptionFilter(LocalUnhandledExceptionFilter); + + std::string error; + if (!o3d::RendererInstallCheck(&error)) { + return false; + } + WNDCLASSEX wc = {0}; + + wc.lpszClassName = L"MY_WINDOWS_CLASS"; + wc.cbSize = sizeof(WNDCLASSEX); + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = ::WindowProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = instance; + wc.hIcon = ::LoadIcon(instance, IDI_APPLICATION); + wc.hIconSm = NULL; + wc.hCursor = ::LoadCursor(instance, IDC_ARROW); + wc.hbrBackground = static_cast<HBRUSH>(::GetStockObject(BLACK_BRUSH)); + wc.lpszMenuName = NULL; + + if (!::RegisterClassEx(&wc)) + return false; + + g_window_handle = ::CreateWindowExW(NULL, + wc.lpszClassName, + L"", + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, + CW_USEDEFAULT, + 512, + 512, + 0, + 0, + instance, + 0); + + if (g_window_handle == NULL) + return false; + + static wchar_t program_filename[512]; + ::GetModuleFileNameW(NULL, program_filename, sizeof(program_filename)); + program_filename[511] = 0; + + std::wstring program_path(program_filename); + std::wstring program_name; + + // Remove all characters starting with last '\'. + size_t backslash_pos = program_path.rfind('\\'); + if (backslash_pos != o3d::String::npos) { + program_name = &program_filename[backslash_pos + 1]; + program_path.erase(backslash_pos); + } else { + program_name = program_path; + } + + o3d::String program_path_utf8 = WideToUTF8(program_path); + o3d::String program_name_utf8 = WideToUTF8(program_name); + g_program_path = &program_path_utf8; + g_program_name = &program_name_utf8; + + o3d::ServiceLocator service_locator; + g_service_locator = &service_locator; + + o3d::EvaluationCounter evaluation_counter(g_service_locator); + o3d::ClassManager class_manager(g_service_locator); + o3d::ObjectManager object_manager(g_service_locator); + o3d::Profiler profiler(g_service_locator); + o3d::Features features(g_service_locator); + + // create a renderer device based on the current platform + g_renderer = o3d::Renderer::CreateDefaultRenderer(g_service_locator); + + // Initialize the renderer for off-screen rendering if kOffScreenRenderer + // is in the environment. + bool success; + o3d::DisplayWindowWindows* display_window = + new o3d::DisplayWindowWindows(); + display_window = display_window; + display_window->set_hwnd(g_window_handle); + g_display_window = display_window; + bool offscreen = ::GetEnvironmentVariableW(kOffScreenRenderer, NULL, 0); + if (offscreen) { + success = + g_renderer->Init(*g_display_window, true) == o3d::Renderer::SUCCESS; + } else { + success = + g_renderer->Init(*g_display_window, false) == o3d::Renderer::SUCCESS; + if (success) { + ::SetWindowPos(g_window_handle, HWND_TOPMOST, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE); + ::ShowWindow(g_window_handle, SW_SHOWNORMAL); + } + } + + int ret = EXIT_FAILURE; + if (!success) { + if (offscreen) { + ::fprintf(stdout, "Failed to initialize OFFSCREEN renderer\n"); + } else { + ::fprintf(stdout, "Failed to initialize on screen renderer\n"); + } + } else { + // Invoke the main entry point with the command-line arguments + int arg_count; + LPWSTR *arg_values = ::CommandLineToArgvW(::GetCommandLine(), &arg_count); + ret = ::test_main(arg_count, arg_values); + ::LocalFree(arg_values); + g_renderer->Destroy(); + } + + delete g_renderer; + g_renderer = NULL; + + delete display_window; + g_display_window = NULL; + g_program_path = NULL; + g_program_name = NULL; + + return ret; +} diff --git a/o3d/tests/common/win/testing_common.h b/o3d/tests/common/win/testing_common.h new file mode 100644 index 0000000..1b282f3 --- /dev/null +++ b/o3d/tests/common/win/testing_common.h @@ -0,0 +1,66 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// Set of external declarations for global objects required for O3D +// testing. + +#ifndef O3D_TESTS_COMMON_WIN_TESTING_COMMON_H__ +#define O3D_TESTS_COMMON_WIN_TESTING_COMMON_H__ + +#include "core/cross/types.h" +#include "gtest/gtest.h" + +namespace o3d { +class ServiceLocator; +class Renderer; +} + +extern o3d::ServiceLocator* g_service_locator; + +// g_renderer should be declared in a separate .cc file. The +// code in this file must remain platform agnostic. +extern o3d::Renderer* g_renderer; + +// Path to the executable, used to load files relative to it. +extern o3d::String *g_program_path; + +// the window handle used to create the current window, used to instance a +// specific Renderer class. +#if defined(OS_WIN) +extern HWND g_window_handle; +#endif +// Un-qualified name of the executable, stripped of all path information. +// Note that the executable extension is included in this string. +extern o3d::String* g_program_name; + + +#endif // O3D_TESTS_COMMON_WIN_TESTING_COMMON_H__ diff --git a/o3d/tests/keyboard_info.html b/o3d/tests/keyboard_info.html new file mode 100644 index 0000000..8e737da --- /dev/null +++ b/o3d/tests/keyboard_info.html @@ -0,0 +1,126 @@ +<!-- +Copyright 2009, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> + <meta http-equiv="content-type" content="text/html; charset=utf-8"> + <title>Keyboard Events</title> + + <style> + div.debug { + border:thin dotted gray; + padding:1em; + height:150px; + overflow:scroll; + } + </style> + + +<script type="text/javascript" charset="utf-8"> + +function propsOf(event) { + var property, propCollection = ""; + for(property in event) + propCollection += (property + ":" + event[property] + "/"); + return propCollection; +} + + +function charValue(c) { + return (c == 0) ? 'none' : String.fromCharCode(c); +} + +function keyPropsOf(event) { + var props = ['type', 'keyCode', 'charCode', 'keyIdentifier', 'which', + 'timeStamp', 'isTrusted']; + var property, propCollection = ""; + for(property in props) { + var pName = props[property]; + propCollection += (pName + ":" + event[pName] + '<br>'); + } + propCollection += 'unicode (char, key): ' + charValue(event.charCode) + ', ' + + charValue(event.keyCode); + return propCollection; +} + +function setField(the_id, the_value) { + var field = document.getElementById(the_id); + field.innerHTML = the_value; +} + +function debugLogEvent(in_event, name) { + var cb = document.getElementById('checkbox'); + var event = (in_event) ? in_event : window.event; + setField(name, ((cb.checked) ? propsOf(event) : keyPropsOf(event))); +} + +function keyUp(event) { + debugLogEvent(event, 'KeyUp_Field'); +} + +function keyDown(event) { + setField('KeyUp_Field', ''); + setField('KeyDown_Field', ''); + setField('KeyPress_Field', ''); + debugLogEvent(event, 'KeyDown_Field'); +} + + +function keyPressed(event) { + debugLogEvent(event, 'KeyPress_Field'); +} + +function init() { + var field = document.getElementById('KeyDown_Field'); + field.focus(); +} + +window.document.onkeypress = keyPressed; +window.document.onkeyup = keyUp; +window.document.onkeydown = keyDown; +window.onload = init; + +</script> +</head> +<body> + +<div id='KeyDown_Field' class='debug'> </div> +<div id='KeyPress_Field' class='debug'> </div> +<div id='KeyUp_Field' class='debug'> </div> +<form> +<br> +<input name="Display All Fields" type="checkbox" id='checkbox'>Display All</input> +</form> + +</body> +</html> diff --git a/o3d/tests/package_tests.bat b/o3d/tests/package_tests.bat new file mode 100644 index 0000000..739f94f --- /dev/null +++ b/o3d/tests/package_tests.bat @@ -0,0 +1,37 @@ +@ECHO OFF +REM Copyright 2009, Google Inc. +REM All rights reserved. +REM +REM Redistribution and use in source and binary forms, with or without +REM modification, are permitted provided that the following conditions are +REM met: +REM +REM * Redistributions of source code must retain the above copyright +REM notice, this list of conditions and the following disclaimer. +REM * Redistributions in binary form must reproduce the above +REM copyright notice, this list of conditions and the following disclaimer +REM in the documentation and/or other materials provided with the +REM distribution. +REM * Neither the name of Google Inc. nor the names of its +REM contributors may be used to endorse or promote products derived from +REM this software without specific prior written permission. +REM +REM THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +REM "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +REM LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +REM A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +REM OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +REM SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +REM LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +REM DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +REM THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +REM (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +REM OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +REM Invoke this script to package all of the dependencies required for the +REM O3D system tests into a single zip file for easy distribution across +REM testing machines. +SET TODAY=%date:~10,4%%date:~4,2%%date:~7,2% +SET ZIPNAME=_test_distribution.zip +..\..\..\..\third_party\7zip_423\files\7z.exe a -tzip %TODAY%%ZIPNAME% o3d.msi d3d9ref.dll Detoured.dll import_test Microsoft.VC80.DebugCRT perceptualdiff.exe PIXAdmin.exe PIXHelper.dll PIXWin.exe system_tests.exe testing_framework_hardware.PIXExp testing_framework_reference.PIXExp test_driver.py diff --git a/o3d/tests/presubmit_tests.bat b/o3d/tests/presubmit_tests.bat new file mode 100644 index 0000000..137d5a7 --- /dev/null +++ b/o3d/tests/presubmit_tests.bat @@ -0,0 +1,35 @@ +REM Copyright 2009, Google Inc. +REM All rights reserved. +REM +REM Redistribution and use in source and binary forms, with or without +REM modification, are permitted provided that the following conditions are +REM met: +REM +REM * Redistributions of source code must retain the above copyright +REM notice, this list of conditions and the following disclaimer. +REM * Redistributions in binary form must reproduce the above +REM copyright notice, this list of conditions and the following disclaimer +REM in the documentation and/or other materials provided with the +REM distribution. +REM * Neither the name of Google Inc. nor the names of its +REM contributors may be used to endorse or promote products derived from +REM this software without specific prior written permission. +REM +REM THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +REM "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +REM LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +REM A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +REM OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +REM SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +REM LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +REM DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +REM THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +REM (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +REM OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +REM This test will invoke all of the O3D unit-tests. Please execute +REM these tests before submitting to P4. +@echo off +echo Invoking Tests +%~dp0\unit_tests.exe +if exist %~dp0\test_driver.bat call %~dp0\test_driver.bat %* diff --git a/o3d/tests/selenium/__init__.py b/o3d/tests/selenium/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/o3d/tests/selenium/__init__.py diff --git a/o3d/tests/selenium/javascript_unit_test_list.txt b/o3d/tests/selenium/javascript_unit_test_list.txt new file mode 100644 index 0000000..9cfa199 --- /dev/null +++ b/o3d/tests/selenium/javascript_unit_test_list.txt @@ -0,0 +1,88 @@ +# +# Test Requirements: +# +# Each sample is expected to have a global variable called g_testResult +# That starts undefined and is set to true or false when the test is finished. +# +# Line Format: +# +# TestType test-name options +# +# Valid TestTypes are: +# +# small +# medium +# large +# +# options are separated by spaces. +# screenshot : take a screenshot. You can specify a time with +# screenshot(seconds) as in screenshot(4), take it at the 4 second mark. +# You have also specify more than 1 screenshot by specifying more than +# one screenshot option as in "screenshot(4), screenshot(6.5). +# +# To take a screenshot the test must have a global variable "g_client" +# that is the client plugin object from which to take a screenshot. +# +# If the sample is animated, it is expected to have a global variable +# called g_timeMult that can be set to 0 to stop the animation. All of +# its animation must be based on a global variable called g_clock, such +# that setting g_clock to the same value will always produce the same +# image. +# +# Screenshots will not be taking unless g_testResult is true. +# +# timeout(milliseconds) : Set the timeout to wait for readiness. Default 5000. +# +# client(client_variable_name) : Name of client variable in javascript. +# Default = "g_client" +# +# pdiff_threshold_mac(number_of_pixels_allowed) +# pdiff_threshold_win(number_of_pixels_allowed) +# pdiff_threshold_linux(number_of_pixels_allowed) +# pdiff_threshold(number_of_pixels_allowed) : Number of pixels +# allowed to be perceptually different before the test fails. +# "pdiff_threshold" specifies the threshold for all +# platforms. Platform specific versions override the +# threshold for that platform. The default threshold is 10 pixels. +# +# except(*firefox, *iexplore, *googlechrome) : Name of the browser +# environment(s) where the test should be skipped. +# Default = "" +# +# NOTE! ---------------------------------------------------------------------- +# +# Read the sample guidelines +# http://wiki.corp.google.com/twiki/bin/view/Main/ClientThreeDSampleGuidelines +# +# +small version-check-test +small event-test +small test-test +small serialization-test +small math-test +small features-test except(*iexplore) +small quaternion-test +small v8-test +small init-status-test +small quaternion-test +small base-test +small util-test +small pixel-perfection screenshot pdiff_threshold(2500) pdiff_threshold_mac(3000) except(*iexplore) +medium offscreen-test +small no-rendergraph screenshot +small non-cachable-params screenshot pdiff_threshold(1700) +small type-test +small render-test +# TODO Test disabled, as the behaviour on Chrome does not match other +# browsers - objects are not deleted properly. +small ownership-test +small effect-import-test + +# -- tests below this line are tests for which there is a python +# function to custom run the test. As such, only the 'except' and +# pdiff_threshold options have any meaning + +medium TestStressDrawShapes +medium TestStressMultiWindow +large TestStressCullingZSort pdiff_threshold(14100) + diff --git a/o3d/tests/selenium/javascript_unit_tests.py b/o3d/tests/selenium/javascript_unit_tests.py new file mode 100644 index 0000000..6d686ee --- /dev/null +++ b/o3d/tests/selenium/javascript_unit_tests.py @@ -0,0 +1,304 @@ +#!/usr/bin/python2.4 +# Copyright 2009, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +"""Runs JavaScript unit tests in Selenium. + +NOTE: If you manually write a test in python (vs using the generic test) +The name of the screenshots must match the name of the test not including +the suffix. In otherwords, if your test is called TestSampleCustomCameraMedium +then your screenshots need to be named customcamera1, customcamera2 etc. + +This is so when it comes time to compare screenshots we can figure out which +reference images require a corresponding screenshot. In other words if +TestSampleCustomCameraMedium is run then we know that any reference file +named customcamera1_reference.png requires that there be a corresponding +screenshot. +""" + + +import selenium_utilities + +class JavaScriptUnitTests(selenium_utilities.SeleniumTestCase): + """Runs the JavaScript unit tests for the sample utilities.""" + + def __init__(self, name, session, browser, test_type=None, sample_path=None, + options=None): + selenium_utilities.SeleniumTestCase.__init__( + self, name, session, browser, test_type, sample_path, options) + + def GenericTest(self): + """Generically test a sample. + + Each sample is expected to have a global variable called g_testResult + That starts undefined and is set to true or false when the test is finished. + """ + self.RunGenericTest( + self.session.browserURL + + "/tests/selenium/tests/", + "typeof(window.g_testResult) != 'undefined'", + "window.g_testResult") + + def TestStressDrawShapes(self): + """Tries to draw a large number of shapes for stress testing.""" + + # Alias for the selenium session + s = self.session + s.open(s.browserURL + + "/tests/selenium/tests/drawshapes.html") + + # Allow a limited time for the plugin to initialize. + s.wait_for_condition("typeof(window.g_client) != 'undefined';", 20000) + + # Sanity checks. + self.assertEqual("Drawshape stress test for O3D", s.get_title()) + self.assertEqual("null", s.get_eval("window.undefined_symbol_xxxyyy")) + + # Check assets for base o3d setup: + # 2 nodes in scene graph + # Root node and g_parent_transform node + self.assertEqual( + "2", + s.get_eval("window.g_client.root.getTransformsInTree().length")) + + # There are 8 nodes in the render graph. + # 1 root render node + # 1 viewport + # 1 clear buffer + # 1 tree traversal + # 2 draw passes + # 2 StateSets + self.assertEqual( + "8", + s.get_eval("window.g_client.renderGraphRoot." + "getRenderNodesInTree().length")) + + # Draw 5 triangles + s.type("numShapes", "5") + s.click("btnTri") + + # 5 more primitives should get created + # (1 for the parent transform) + s.wait_for_condition( + "window.g_client." + "getObjectsByClassName('o3d.Shape').length == 5", + 5000) + # 5 more primitives nodes should get created + self.assertEqual( + "5", + s.get_eval("window.g_client." + "getObjectsByClassName('o3d.Primitive').length")) + + # Draw more triangles + s.type("numShapes", "8") + for i in range(1, 10): + s.click("btnTri") + s.wait_for_condition( + "window.g_client." + "getObjectsByClassName('o3d.Shape').length == %d" % (5 + i * 8), + 5000) + self.assertEqual( + str(5 + i * 8), + s.get_eval("window.g_client." + "getObjectsByClassName('o3d.Primitive').length")) + + # Clear triangles, reset pack. + s.click("btnClear") + + # Check assets for base o3d setup again. + self.assertEqual( + "2", + s.get_eval("window.g_client.root.getTransformsInTree().length")) + self.assertEqual( + "8", + s.get_eval("window.g_client.renderGraphRoot." + "getRenderNodesInTree().length")) + + # Now draw lines + s.type("numShapes", "5") + s.click("btnLines") + + # 5 more shapes should get created + # (1 for the parent transform) + s.wait_for_condition( + "window.g_client." + "getObjectsByClassName('o3d.Shape').length == 5", + 5000) + # 5 more primitives and drawelements should get created + self.assertEqual( + "5", + s.get_eval("window.g_client." + "getObjectsByClassName('o3d.Primitive').length")) + self.assertEqual( + "5", + s.get_eval("window.g_client." + "getObjectsByClassName('o3d.DrawElement').length")) + + # Draw more lines + s.type("numShapes", "11") + for i in range(1, 10): + s.click("btnLines") + s.wait_for_condition( + "window.g_client." + "getObjectsByClassName('o3d.Shape').length == %d" % (5 + i * 11), + 5000) + self.assertEqual( + str(5 + i * 11), + s.get_eval("window.g_client." + "getObjectsByClassName('o3d.Primitive').length")) + + # Clear triangles, reset pack. + s.click("btnClear") + + # Check assets for base o3d setup again. + self.assertEqual( + "2", + s.get_eval("window.g_client.root.getTransformsInTree().length")) + self.assertEqual( + "8", + s.get_eval("window.g_client.renderGraphRoot." + "getRenderNodesInTree().length")) + + # Now draw 1000 triangles + s.type("numShapes", "1000") + s.click("btnTri") + + # 30 seconds to draw 1000 triangle shapes + s.wait_for_condition( + "window.g_client." + "getObjectsByClassName('o3d.Shape').length == 1000", + 30000) + # Assert number of primitives + self.assertEqual( + "1000", + s.get_eval("window.g_client." + "getObjectsByClassName('o3d.Primitive').length")) + + # Clear triangles, reset pack. + s.click("btnClear") + + def TestStressMultiWindow(self): + """Opens 5 windows of simpletexture.html.""" + + # Alias for the selenium session + s = self.session + + # Save the titles of windows so we can reset the current window. + # Note: docs of selenium are out of date. We should be able to use ids or + # names in select_window below but all of those methods failed. + old = s.get_all_window_titles() + + for i in range(1, 5): + s.open_window(s.browserURL + + "/samples/simpletexture.html", + "o3dstress_window%d" % i) + + for i in range(1, 5): + s.select_window("o3dstress_window%d" % i) + # Allow a limited time for the plugin to initialize. + s.wait_for_condition("typeof(window.g_client) != 'undefined';", 30000) + + # Sanity checks. + self.assertEqual("Tutorial B3: Textures", s.get_title()) + self.assertEqual("null", s.get_eval("window.undefined_symbol_xxxyyy")) + + for i in range(1, 5): + s.select_window("o3dstress_window%d" % i) + s.close() + + # make the old window the current window so the next test will run. + s.select_window(old[0]) + + def TestStressCullingZSort(self): + """Checks culling and zsorting work.""" + + # Alias for the selenium session + s = self.session + s.open(s.browserURL + + "/tests/selenium/tests/culling-zsort-test.html") + + # Allow a limited time for the plugin to initialize. + s.wait_for_condition("typeof(window.g_client) != 'undefined';", 20000) + + # Sanity checks. + self.assertEqual("Culling and ZSorting Test.", s.get_title()) + self.assertEqual("null", s.get_eval("window.undefined_symbol_xxxyyy")) + s.wait_for_condition("window.g_client != null", 10000) + + # Wait for all instances to be created. + s.wait_for_condition( + "window.g_totalDrawElementsElement.innerHTML == '2'", + 40000) + + # Stop animation + s.run_script("g_timeMult = 0") + s.run_script("g_client.renderMode = g_o3d.Client.RENDERMODE_ON_DEMAND") + s.run_script("var g_rendered = false") + + new_data = [] + culling_reference_data = [[1793, 4472, 3780, 2, 4844, 213, 4631], + [1793, 6011, 3854, 2, 7734, 337, 7397], + [1793, 3014, 2416, 2, 3400, 121, 3279], + [1793, 2501, 2408, 2, 2420, 162, 2258], + [1793, 2933, 2914, 2, 2746, 182, 2564], + [1793, 2825, 2848, 2, 2604, 171, 2433], + [1793, 2933, 2790, 2, 2870, 155, 2715], + [1793, 4337, 3004, 2, 5360, 237, 5123]] + + # Take screenshots + for clock in range(0, 8): + s.run_script("window.g_clock = " + str(clock * 3.14159 * 2.5 + 0.5)) + self.assertTrue( + selenium_utilities.TakeScreenShot(s, self.browser, "window.g_client", + "cullingzsort" + str(clock))) + s.run_script("g_framesRendered = 0") + while int(s.get_eval("window.g_framesRendered")) < 3: + s.run_script("window.g_client.render()") + data = [s.get_eval("window.g_totalTransformsElement.innerHTML"), + s.get_eval("window.g_transformsProcessedElement.innerHTML"), + s.get_eval("window.g_transformsCulledElement.innerHTML"), + s.get_eval("window.g_totalDrawElementsElement.innerHTML"), + s.get_eval("window.g_drawElementsProcessedElement.innerHTML"), + s.get_eval("window.g_drawElementsCulledElement.innerHTML"), + s.get_eval("window.g_drawElementsRenderedElement.innerHTML")] + new_data.append(data) + print ", ".join(data) + + # check the results + for clock in range(0, 8): + for ii in range(0, 7): + # comment out the following line and add a "pass" line if you need new + # culling reference data. + self.assertEqual(int(new_data[clock][ii]), + culling_reference_data[clock][ii]) + + +if __name__ == "__main__": + pass diff --git a/o3d/tests/selenium/main.py b/o3d/tests/selenium/main.py new file mode 100644 index 0000000..cb40b95 --- /dev/null +++ b/o3d/tests/selenium/main.py @@ -0,0 +1,954 @@ +#!/usr/bin/python2.4 +# Copyright 2009, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +"""Selenium tests for the O3D plugin. + +Sets up a local Selenium Remote Control server and a static file +server that serves files off the o3d directory. + +Launches browsers to test the local build of the o3d plugin +and reports results back to the user. +""" + + + +import os +import platform +import re +import SimpleHTTPServer +import socket +import SocketServer +import subprocess +import sys +import threading +import time +import unittest +import gflags +import javascript_unit_tests +# Import custom testrunner for pulse +import pulse_testrunner +# TODO: figure out if we can remove this hard-coded version +import rev2478_mod as selenium +import samples_tests +import selenium_constants +import selenium_utilities + + +if platform.system() == "Windows": + default_java_exe = "java.exe" +else: + default_java_exe = "java" + +# Commands line flags +FLAGS = gflags.FLAGS +gflags.DEFINE_boolean("verbose", False, "verbosity") +gflags.DEFINE_boolean("screenshots", False, "takes screenshots") +gflags.DEFINE_string( + "java", + default_java_exe, + "specifies the path to the java executable.") +gflags.DEFINE_string( + "selenium_server", + "", + "specifies the path to the selenium server jar.") +gflags.DEFINE_string( + "screencompare", + "", + "specifies the directory in which perceptualdiff resides.\n" + "compares screenshots with reference images") +gflags.DEFINE_string( + "screenshotsdir", + selenium_constants.DEFAULT_SCREENSHOT_PATH, + "specifies the directory in which screenshots will be stored.") +gflags.DEFINE_string( + "referencedir", + selenium_constants.DEFAULT_SCREENSHOT_PATH, + "Specifies the directory where reference images will be read from.") +gflags.DEFINE_string( + "testprefix", "Test", + "specifies the prefix of tests to run") +gflags.DEFINE_string( + "testsuffixes", "", + "specifies the suffixes, separated by commas of tests to run") +gflags.DEFINE_string( + "servertimeout", "30", + "Specifies the timeout value, in seconds, for the selenium server.") + +# Browsers to choose from (for browser flag). +# use --browser $BROWSER_NAME to run +# tests for that browser +gflags.DEFINE_list( + "browser", + "*firefox", + "\n".join(["comma-separated list of browsers to test", + "Options:"] + + selenium_constants.SELENIUM_BROWSER_SET)) +gflags.DEFINE_string( + "browserpath", + "", + "specifies the path to the browser executable " + "(for platforms that don't support MOZ_PLUGIN_PATH)") + +TESTING_ROOT = os.path.abspath(os.path.dirname(__file__) + "/..") + + +class MyRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): + """Hook to handle HTTP server requests. + + Functions as a handler for logging and other utility functions. + """ + + def log_message(self, format, *args): + """Logging hook for HTTP server.""" + + # For now, just suppress logging. + pass + # TODO: might be nice to have a verbose option for debugging. + + +class LocalFileHTTPServer(threading.Thread): + """Minimal HTTP server that serves local files. + + Members: + http_alive: event to signal that http server is up and running + http_port: the TCP port the server is using + """ + + START_PORT = 8100 + END_PORT = 8105 + + def __init__(self, local_root=None): + """Initializes the server. + + Initializes the HTTP server to serve static files from the + local o3d directory + + Args: + local_root: all files below this path are served. If not specified, + the current directory is the root. + """ + threading.Thread.__init__(self) + self._local_root = local_root + self.http_alive = threading.Event() + self.http_port = 0 + + def run(self): + """Runs the HTTP server. + + Server is started on an available port in the range of + START_PORT to END_PORT + """ + + if self._local_root: + os.chdir(self._local_root) + + for self.http_port in range(self.START_PORT, self.END_PORT): + # Attempt to start the server + try: + httpd = SocketServer.TCPServer(("", self.http_port), + MyRequestHandler) + except socket.error: + # Server didn't manage to start up, try another port. + pass + else: + self.http_alive.set() + httpd.serve_forever() + + if not self.http_alive.isSet(): + print("No available port found for HTTP server in the range %d to %d." + % (self.START_PORT, self.END_PORT)) + + @staticmethod + def StartServer(local_root=None): + """Create and start a LocalFileHTTPServer on a separate thread. + + Args: + local_root: serve all static files below this directory. If not + specified, the current directory is the root. + + Returns: + http_server: LocalFileHTTPServer() object + """ + + # Start up the Selenium Remote Control server + http_server = LocalFileHTTPServer(local_root) + http_server.setDaemon(True) + http_server.start() + + # Wait till the Selenium RC Server is up + http_server.http_alive.wait() + + print "LocalFileHTTPServer started on port %d" % http_server.http_port + + return http_server + + +class SeleniumRemoteControl(threading.Thread): + """A thread that launches the Selenium Remote Control server. + + The Remote Control server allows us to launch a browser and remotely + control it from a script. + + Members: + selenium_alive: event to signal that selenium server is up and running + selenium_port: the TCP port the server is using + process: the subprocess.Popen instance for the server + """ + + START_PORT = 5430 + END_PORT = 5535 + + def __init__(self, verbose, java_path, selenium_server, server_timeout): + """Initializes the SeleniumRemoteControl class. + + Args: + verbose: boolean verbose flag + java_path: path to java used to run selenium. + selenium_server: path to jar containing selenium server. + server_timeout: server timeout value, in seconds. + """ + self.selenium_alive = threading.Event() + self.selenium_port = 0 + self.verbose = verbose + self.java_path = java_path + self.selenium_server = selenium_server + self.timeout = server_timeout + threading.Thread.__init__(self) + + def run(self): + """Starts the selenium server. + + Server is started on an available port in the range of + START_PORT to END_PORT + """ + + for self.selenium_port in range(self.START_PORT, self.END_PORT): + # Attempt to start the selenium RC server from java + self.process = subprocess.Popen( + [self.java_path, "-jar", self.selenium_server, "-multiWindow", + "-port", str(self.selenium_port), "-timeout", self.timeout], + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + + for unused_i in range(1, 10): + server_msg = self.process.stdout.readline() + if self.verbose and server_msg is not None: + # log if verbose flag is on + print "sel_serv:" + server_msg + + # This status message indicates that the server has done + # a bind to the port self.selenium_port successfully. + if server_msg.find("INFO - Started SocketListener") != -1: + self.selenium_alive.set() + break + + # Error starting server on this port, try the next port. + if not self.selenium_alive.isSet(): + continue + + # Loop and read from stdout + while self.process.poll() is None: + server_msg = self.process.stdout.readline() + if self.verbose and server_msg is not None: + # log if verbose flag is on + print "sel_serv:" + server_msg + + # Finish. + break + + if not self.selenium_alive.isSet(): + print("No available port found for Selenium RC Server " + "in the range %d to %d." + % (self.START_PORT, self.END_PORT)) + + @staticmethod + def StartServer(verbose, java_path, selenium_server, server_timeout): + """Create and start the Selenium RC Server on a separate thread. + + Args: + verbose: boolean verbose flag + java_path: path to java used to run selenium. + selenium_server: path to jar containing selenium server. + server_timeout: server timeout value, in seconds + + Returns: + selenium_server: SeleniumRemoteControl() object + """ + + # Start up the Selenium Remote Control server + selenium_server = SeleniumRemoteControl(verbose, + java_path, + selenium_server, + server_timeout) + selenium_server.setDaemon(True) + selenium_server.start() + + # Wait till the Selenium RC Server is up + selenium_server.selenium_alive.wait() + + print("Selenium RC server started on port %d" + % selenium_server.selenium_port) + + return selenium_server + + +class SeleniumSession(object): + """A selenium browser session, with support servers. + + The support servers include a Selenium Remote Control server, and + a local HTTP server to serve static test files. + + Members: + session: a selenium() instance + selenium_server: a SeleniumRemoteControl() instance + http_server: a LocalFileHTTPServer() instance + runner: a TestRunner() instance + """ + + def __init__(self, verbose, java_path, selenium_server, server_timeout): + """Initializes a Selenium Session. + + Args: + verbose: boolean verbose flag + java_path: path to java used to run selenium. + selenium_server: path to jar containing selenium server. + server_timeout: server timeout value, in seconds + """ + # Start up a static file server, to serve the test pages. + # Serve from the o3d directory + self.http_server = LocalFileHTTPServer.StartServer( + TESTING_ROOT + "/../") + + # Start up the Selenium Remote Control Server + self.selenium_server = SeleniumRemoteControl.StartServer(verbose, + java_path, + selenium_server, + server_timeout) + + # Set up a testing runner + self.runner = pulse_testrunner.PulseTestRunner() + + # Set up a phantom selenium session so we can call shutdown if needed. + self.session = selenium.selenium( + "localhost", self.selenium_server.selenium_port, "*firefox", + "http://" + socket.gethostname() + ":" + + str(self.http_server.http_port)) + + def StartSession(self, browser): + """Starts the Selenium Session and connects to the HTTP server. + + Args: + browser: selenium browser name + """ + + if browser == "*googlechrome": + # TODO: Replace socket.gethostname() with "localhost" + # once Chrome local proxy fix is in. + server_url = "http://" + socket.gethostname() + ":" + else: + server_url = "http://localhost:" + server_url += str(self.http_server.http_port) + browser_path_with_space = FLAGS.browserpath + + # TODO: This is a hack to figure out if we're on 64-bit + # Windows. If we are, then we have to run the 32-bit Internet + # Explorer so that our plugin will work (indeed, even Microsoft + # has even made it impossible to use 64-bit Internet Explorer as + # your default browser). We need to find a better way to + # determine if we're on 64-bit Windows, so that it will work on + # foreign machines (which don't use the strings below for "Program + # Files" and "Internet Explorer"). + if (not browser_path_with_space and + browser == "*iexplore"): + program_files_x86 = "C:\\Program Files (x86)" + if os.path.isdir(program_files_x86): + browser_path_with_space = os.path.join(program_files_x86, + "Internet Explorer", + "iexplore.exe") + + if browser_path_with_space: + browser_path_with_space = " " + browser_path_with_space + self.session = selenium.selenium("localhost", + self.selenium_server.selenium_port, + browser + browser_path_with_space, + server_url) + self.session.start() + + def CloseSession(self): + """Closes the selenium sesssion.""" + self.session.stop() + + def TearDown(self): + """Stops the selenium server.""" + self.session.do_command("shutDown", []) + # Sync with selenium_server thread + self.selenium_server.join() + + def TestBrowser(self, browser, test_list, test_prefix, test_suffixes, + server_timeout): + """Runs Selenium tests for a specific browser. + + Args: + browser: selenium browser name (eg. *iexplore, *firefox). + test_list: list to add tests to. + test_prefix: prefix of tests to run. + test_suffixes: comma separated suffixes of tests to run. + server_timeout: server timeout value, in milliseconds + + Returns: + result: result of test runner. + """ + print "Testing %s..." % browser + self.StartSession(browser) + self.session.set_timeout(server_timeout) + self.runner.setBrowser(browser) + + try: + result = self.runner.run( + SeleniumSuite(self.session, browser, test_list, + test_prefix, test_suffixes)) + finally: + self.CloseSession() + + return result + + +class LocalTestSuite(unittest.TestSuite): + """Wrapper for unittest.TestSuite so we can collect the tests.""" + + def __init__(self): + unittest.TestSuite.__init__(self) + self.test_list = [] + + def addTest(self, name, test): + """Adds a test to the TestSuite and records its name and test_path. + + Args: + name: name of test. + test: test to pass to unittest.TestSuite. + """ + unittest.TestSuite.addTest(self, test) + try: + self.test_list.append((name, test.options)) + except AttributeError: + self.test_list.append((name, [])) + + +def MatchesSuffix(name, suffixes): + """Checks if a name ends in one of the suffixes. + + Args: + name: Name to test. + suffixes: list of suffixes to test for. + Returns: + True if name ends in one of the suffixes or if suffixes is empty. + """ + if suffixes: + name_lower = name.lower() + for suffix in suffixes: + if name_lower.endswith(suffix): + return True + return False + else: + return True + + +def AddTests(test_suite, session, browser, module, filename, prefix, + test_prefix_filter, test_suffixes): + """Add tests defined in filename. + + Assumes module has a method "GenericTest" that uses self.args to run. + + Args: + test_suite: A Selenium test_suite to add tests to. + session: a Selenium instance. + browser: browser name. + module: module which will have method GenericTest() called to run each test. + filename: filename of file with list of tests. + prefix: prefix to add to the beginning of each test. + test_prefix_filter: Only adds a test if it starts with this. + test_suffixes: list of suffixes to filter by. An empty list = pass all. + """ + # See comments in that file for the expected format. + # skip lines that are blank or have "#" or ";" as their first non whitespace + # character. + test_list_file = open(filename, "r") + samples = test_list_file.readlines() + test_list_file.close() + + for sample in samples: + sample = sample.strip() + if not sample or sample[0] == ";" or sample[0] == "#": + continue + + arguments = sample.split() + test_type = arguments[0].lower() + test_path = arguments[1] + options = arguments[2:] + + # TODO: Add filter based on test_type + + name = ("Test" + prefix + re.sub("\W", "_", test_path) + + test_type.capitalize()) + + # Only execute this test if the current browser is not in the list + # of skipped browsers. + test_skipped = False + for option in options: + if option.startswith("except"): + skipped_platforms = selenium_utilities.GetArgument(option) + if not skipped_platforms is None: + skipped_platforms = skipped_platforms.split(",") + if browser in skipped_platforms: + test_skipped = True + + if not test_skipped: + # Check if there is already a test function by this name in the module. + if (test_path.startswith(test_prefix_filter) and + hasattr(module, test_path) and callable(getattr(module, test_path))): + test_suite.addTest(test_path, module(test_path, session, browser, + options=options)) + elif (name.startswith(test_prefix_filter) and + MatchesSuffix(name, test_suffixes)): + # no, so add a method that will run a test generically. + setattr(module, name, module.GenericTest) + test_suite.addTest(name, module(name, session, browser, + test_type, test_path, options)) + + +def SeleniumSuite(session, browser, test_list, test_prefix, test_suffixes): + """Creates a test suite to run the unit tests. + + Args: + session: a selenium() instance + browser: browser name + test_list: list to add tests to. + test_prefix: prefix of tests to run. + test_suffixes: A comma separated string of suffixes to filter by. + Returns: + A selenium test suite. + """ + + test_suite = LocalTestSuite() + + suffixes = test_suffixes.split(",") + + # add sample tests. + filename = os.path.join(os.getcwd(), "tests", "selenium", "sample_list.txt") + AddTests(test_suite, + session, + browser, + samples_tests.SampleTests, + filename, + "Sample", + test_prefix, + suffixes) + + # add javascript tests. + filename = os.path.join(os.getcwd(), "tests", "selenium", + "javascript_unit_test_list.txt") + AddTests(test_suite, + session, + browser, + javascript_unit_tests.JavaScriptUnitTests, + filename, + "UnitTest", + test_prefix, + suffixes) + + test_list += test_suite.test_list + + return test_suite + + +def CompareScreenshots(browser, test_list, screencompare, screenshotsdir, + screencompare_tool, verbose): + """Performs the image validation for test-case frame captures. + + Args: + browser: selenium browser name + test_list: list of tests that ran. + screencompare: True to actually run tests. + screenshotsdir: path of directory containing images to compare. + screencompare_tool: path to image diff tool. + verbose: If True then outputs verbose info. + + Returns: + A Results object. + """ + print "Validating captured frames against reference data..." + + class Results(object): + """An object to return results of screenshot compares. + + Similar to unittest.TestResults. + """ + + def __init__(self): + object.__init__(self) + self.tests_run = 0 + self.current_test = None + self.errors = [] + self.failures = [] + self.start_time = 0 + + def StartTest(self, test): + """Adds a test. + + Args: + test: name of test. + """ + self.start_time = time.time() + self.tests_run += 1 + self.current_test = test + + def TimeTaken(self): + """Returns the time since the last call to StartTest.""" + return time.time() - self.start_time + + def AddFailure(self, test, browser, message): + """Adds a failure. + + Args: + test: name of the test. + browser: name of the browser. + message: error message to print + """ + self.failures.append(test) + print "ERROR: ", message + print("SELENIUMRESULT %s <%s> [%.3fs]: FAIL" + % (test, browser, self.TimeTaken())) + + def AddSuccess(self, test): + """Adds a success. + + Args: + test: name of the test. + """ + print("SELENIUMRESULT %s <%s> [%.3fs]: PASS" + % (test, browser, self.TimeTaken())) + + def WasSuccessful(self): + """Returns true if all tests were successful.""" + return not self.errors and not self.failures + + results = Results() + + if not screencompare: + return results + + base_path = os.getcwd() + + reference_files = os.listdir(os.path.join( + base_path, + selenium_constants.REFERENCE_SCREENSHOT_PATH)) + + generated_files = os.listdir(os.path.join(base_path, screenshotsdir)) + + # Prep the test list for matching + temp = [] + for (test, options) in test_list: + test = selenium_utilities.StripTestTypeSuffix(test) + temp.append((test.lower(), options)) + test_list = temp + + # Create regex object for filename + # file is in format "FILENAME_reference.png" + reference_file_name_regex = re.compile(r"^(.*)_reference\.png") + generated_file_name_regex = re.compile(r"^(.*)\.png") + + # check that there is a reference file for each generated file. + for file_name in generated_files: + match = generated_file_name_regex.search(file_name) + + if match is None: + # no matches + continue + + # Generated file name without png extension + actual_name = match.group(1) + + # Get full paths to reference and generated files + reference_file = os.path.join( + base_path, + selenium_constants.REFERENCE_SCREENSHOT_PATH, + actual_name + "_reference.png") + generated_file = os.path.join( + base_path, + screenshotsdir, + actual_name + ".png") + + test_name = "TestReferenceScreenshotExists_" + actual_name + results.StartTest(test_name) + if not os.path.exists(reference_file): + # reference file does not exist + results.AddFailure( + test_name, browser, + "Missing reference file %s for generated file %s." % + (reference_file, generated_file)) + else: + results.AddSuccess(test_name) + + # Assuming both the result and reference image sets are the same size, + # verify that corresponding images are similar within tolerance. + for file_name in reference_files: + match = reference_file_name_regex.search(file_name) + + if match is None: + # no matches + continue + + # Generated file name without png extension + actual_name = match.group(1) + # Get full paths to reference and generated files + reference_file = os.path.join( + base_path, + selenium_constants.REFERENCE_SCREENSHOT_PATH, + file_name) + platform_specific_reference_file = os.path.join( + base_path, + selenium_constants.PLATFORM_SPECIFIC_REFERENCE_SCREENSHOT_PATH, + actual_name + "_reference.png") + generated_file = os.path.join( + base_path, + screenshotsdir, + actual_name + ".png") + + # Generate a test case name + test_name = "TestScreenCompare_" + actual_name + + # skip the reference file if the test is not in the test list. + basename = os.path.splitext(os.path.basename(file_name))[0] + basename = re.sub("\d+_reference", "", basename).lower() + basename = re.sub("\W", "_", basename) + test_was_run = False + test_options = [] + for (test, options) in test_list: + if test.endswith(basename): + test_was_run = True + test_options = options or [] + break + + if test_was_run: + results.StartTest(test_name) + else: + # test was not planned to run for this reference image. + if os.path.exists(generated_file): + # a generated file exists? The test name does not match the screenshot. + results.StartTest(test_name) + results.AddFailure(test_name, browser, + "Test name and screenshot name do not match.") + continue + + # Check if there is a platform specific version of the reference image + if os.path.exists(platform_specific_reference_file): + reference_file = platform_specific_reference_file + + # Check if perceptual diff exists + pdiff_path = os.path.join(base_path, screencompare_tool) + if not os.path.exists(pdiff_path): + # Perceptualdiff.exe does not exist, fail. + results.AddFailure( + test_name, browser, + "Perceptual diff %s does not exist." % pdiff_path) + continue + + pixel_threshold = "10" + use_colorfactor = False + use_downsample = False + + # Find out if the test specified any options relating to perceptual diff + # that will override the defaults. + for opt in test_options: + if opt.startswith("pdiff_threshold"): + pixel_threshold = selenium_utilities.GetArgument(opt) + elif (opt.startswith("pdiff_threshold_mac") and + platform.system() == "Darwin"): + pixel_threshold = selenium_utilities.GetArgument(opt) + elif (opt.startswith("pdiff_threshold_win") and + platform.system() == "Microsoft"): + pixel_threshold = selenium_utilities.GetArgument(opt) + elif (opt.startswith("pdiff_threshold_linux") and + platform.system() == "Linux"): + pixel_threshold = selenium_utilities.GetArgument(opt) + elif (opt.startswith("colorfactor")): + colorfactor = selenium_utilities.GetArgument(opt) + use_colorfactor = True + elif (opt.startswith("downsample")): + downsample_factor = selenium_utilities.GetArgument(opt) + use_downsample = True + + # Check if file exists + if os.path.exists(generated_file): + diff_file = os.path.join(base_path, screenshotsdir, + "compare_%s.png" % actual_name) + + # Run perceptual diff + arguments = [pdiff_path, + reference_file, + generated_file, + "-output", diff_file, + "-fov", "45", + # Turn on verbose output for the percetual diff so we + # can see how far off we are on the threshold. + "-verbose", + # Set the threshold to zero so we can get a count + # of the different pixels. This causes the program + # to return failure for most images, but we can compare + # the values ourselves below. + "-threshold", "0"] + if use_colorfactor: + arguments += ["-colorfactor", colorfactor] + if use_downsample: + arguments += ["-downsample", downsample_factor] + + # Print the perceptual diff command line so we can debug easier. + if verbose: + print " ".join(arguments) + + # diff tool should return 0 on success + expected_result = 0 + + pdiff_pipe = subprocess.Popen(arguments, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + (pdiff_stdout, pdiff_stderr) = pdiff_pipe.communicate() + result = pdiff_pipe.returncode + + # Find out how many pixels were different by looking at the output. + pixel_re = re.compile("(\d+) pixels are different", re.DOTALL) + pixel_match = pixel_re.search(pdiff_stdout) + different_pixels = "0" + if pixel_match: + different_pixels = pixel_match.group(1) + + if (result == expected_result or (pixel_match and + int(different_pixels) <= int(pixel_threshold))): + # The perceptual diff passed. + pass_re = re.compile("PASS: (.*?)\n", re.DOTALL) + pass_match = pass_re.search(pdiff_stdout) + reason = "Images are not perceptually different." + if pass_match: + reason = pass_match.group(1) + print ("%s PASSED with %s different pixels " + "(threshold %s) because: %s" % (test_name, + different_pixels, + pixel_threshold, + reason)) + results.AddSuccess(test_name) + else: + # The perceptual diff failed. + if pixel_match and int(different_pixels) > int(pixel_threshold): + results.AddFailure( + test_name, browser, + ("Reference framebuffer (%s) does not match generated " + "file (%s): it differed by %s pixels with a threshold of %s." % + (reference_file, generated_file, different_pixels, + pixel_threshold))) + else: + # The perceptual diff failed for some reason other than + # pixel differencing. + fail_re = re.compile("FAIL: (.*?)\n", re.DOTALL) + fail_match = fail_re.search(pdiff_stdout) + reason = "Unknown failure" + if fail_match: + reason = fail_match.group(1) + results.AddFailure( + test_name, browser, + ("Perceptual diff of reference (%s) and generated (%s) files " + "failed because: %s" % + (reference_file, generated_file, reason))) + else: + # Generated file does not exist + results.AddFailure(test_name, browser, + "File %s does not exist." % generated_file) + + return results + + +def main(unused_argv): + # Boolean to record if all tests passed. + all_tests_passed = True + + selenium_constants.REFERENCE_SCREENSHOT_PATH = os.path.join( + FLAGS.referencedir, + "reference", + "") + selenium_constants.PLATFORM_SPECIFIC_REFERENCE_SCREENSHOT_PATH = os.path.join( + FLAGS.referencedir, + selenium_constants.PLATFORM_SCREENSHOT_DIR, + "") + + # Open a new session to Selenium Remote Control + selenium_session = SeleniumSession(FLAGS.verbose, FLAGS.java, + FLAGS.selenium_server, + FLAGS.servertimeout) + for browser in FLAGS.browser: + if browser in set(selenium_constants.SELENIUM_BROWSER_SET): + test_list = [] + result = selenium_session.TestBrowser(browser, test_list, + FLAGS.testprefix, + FLAGS.testsuffixes, + int(FLAGS.servertimeout) * 1000) + + # Compare screenshots + compare_result = CompareScreenshots(browser, + test_list, + FLAGS.screenshots, + FLAGS.screenshotsdir, + FLAGS.screencompare, + FLAGS.verbose) + if not result.wasSuccessful() or not compare_result.WasSuccessful(): + all_tests_passed = False + # Log results + print "Results for %s:" % browser + print " %d tests run." % (result.testsRun + compare_result.tests_run) + print " %d errors." % (len(result.errors) + len(compare_result.errors)) + print " %d failures.\n" % (len(result.failures) + + len(compare_result.failures)) + + else: + print "ERROR: Browser %s is invalid." % browser + print "Run with --help to view list of supported browsers.\n" + all_tests_passed = False + + # Wrap up session + selenium_session.TearDown() + + if all_tests_passed: + # All tests successful. + return 0 + else: + # Return error code 1. + return 1 + +if __name__ == "__main__": + remaining_argv = FLAGS(sys.argv) + main(remaining_argv) diff --git a/o3d/tests/selenium/pulse_testrunner.py b/o3d/tests/selenium/pulse_testrunner.py new file mode 100644 index 0000000..71f7bb3 --- /dev/null +++ b/o3d/tests/selenium/pulse_testrunner.py @@ -0,0 +1,149 @@ +#!/usr/bin/python2.4 +# Copyright 2009, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +"""Test runner that displays customized results for pulse. + +Instead of the usual '.', 'E', and 'F' symbols, more detailed +results are printed after each test. + +ie. 'TESTRESULT $TESTNAME: {PASS/FAIL}' +""" + + + +import sys +import time +import unittest + + +# Disable lint errors about functions having to start with upper case. +# This is done to standardize the case of all functions in this class. +# pylint: disable-msg=C6409 +class _PulseTestResult(unittest.TestResult): + """A specialized class that prints formatted text results to a stream. + + Test results are formatted to be recognized in pulse. + Used by PulseTestRunner. + """ + separator1 = "=" * 70 + separator2 = "-" * 70 + + def __init__(self, stream, descriptions, verbosity, browser): + unittest.TestResult.__init__(self) + self.stream = stream + self.show_all = verbosity > 1 + self.dots = verbosity == 1 + self.descriptions = descriptions + # Dictionary of start times + self.start_times = {} + # Dictionary of results + self.results = {} + self.browser = browser + + def getDescription(self, test): + """Gets description of test.""" + if self.descriptions: + return test.shortDescription() or str(test) + else: + return str(test) + + def startTest(self, test): + """Starts test.""" + # Records the start time + self.start_times[test] = time.time() + # Default testresult if success not called + self.results[test] = "FAIL" + unittest.TestResult.startTest(self, test) + if self.show_all: + self.stream.write(self.getDescription(test)) + self.stream.write(" ... ") + + def stopTest(self, test): + """Called when test is ended.""" + time_taken = time.time() - self.start_times[test] + result = self.results[test] + self.stream.writeln("SELENIUMRESULT %s <%s> [%.3fs]: %s" + % (test, self.browser, time_taken, result)) + + def addSuccess(self, test): + """Adds success result to TestResult.""" + unittest.TestResult.addSuccess(self, test) + self.results[test] = "PASS" + + def addError(self, test, err): + """Adds error result to TestResult.""" + unittest.TestResult.addError(self, test, err) + self.results[test] = "FAIL" + + def addFailure(self, test, err): + """Adds failure result to TestResult.""" + unittest.TestResult.addFailure(self, test, err) + self.results[test] = "FAIL" + + def printErrors(self): + """Prints all errors and failures.""" + if self.dots or self.show_all: + self.stream.writeln() + self.printErrorList("ERROR", self.errors) + self.printErrorList("FAIL", self.failures) + + def printErrorList(self, flavour, errors): + """Prints a given list of errors.""" + for test, err in errors: + self.stream.writeln(self.separator1) + self.stream.writeln("%s: %s" % (flavour, self.getDescription(test))) + self.stream.writeln(self.separator2) + self.stream.writeln("%s" % err) + + +class PulseTestRunner(unittest.TextTestRunner): + """A specialized test runner class that displays results in textual form. + + Test results are formatted to be recognized in pulse. + """ + + def __init__(self, stream=sys.stderr, descriptions=1, verbosity=1): + self.browser = "default_browser" + unittest.TextTestRunner.__init__(self, stream, descriptions, verbosity) + + def setBrowser(self, browser): + """Sets the browser name.""" + self.browser = browser + + def _makeResult(self): + """Returns a formatted test result for pulse.""" + return _PulseTestResult(self.stream, + self.descriptions, + self.verbosity, + self.browser) + +if __name__ == "__main__": + pass diff --git a/o3d/tests/selenium/run.bat b/o3d/tests/selenium/run.bat new file mode 100644 index 0000000..3305ef8 --- /dev/null +++ b/o3d/tests/selenium/run.bat @@ -0,0 +1,34 @@ +@echo off +REM Copyright 2009, Google Inc. +REM All rights reserved. +REM +REM Redistribution and use in source and binary forms, with or without +REM modification, are permitted provided that the following conditions are +REM met: +REM +REM * Redistributions of source code must retain the above copyright +REM notice, this list of conditions and the following disclaimer. +REM * Redistributions in binary form must reproduce the above +REM copyright notice, this list of conditions and the following disclaimer +REM in the documentation and/or other materials provided with the +REM distribution. +REM * Neither the name of Google Inc. nor the names of its +REM contributors may be used to endorse or promote products derived from +REM this software without specific prior written permission. +REM +REM THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +REM "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +REM LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +REM A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +REM OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +REM SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +REM LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +REM DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +REM THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +REM (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +REM OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +echo Setting up python environment.. +call %~dp0..\..\..\third_party\python_24\setup_env.bat +echo Starting selenium tests.. +%~dp0..\..\..\third_party\python_24\python.exe main.py %* diff --git a/o3d/tests/selenium/sample_list.txt b/o3d/tests/selenium/sample_list.txt new file mode 100644 index 0000000..699a888 --- /dev/null +++ b/o3d/tests/selenium/sample_list.txt @@ -0,0 +1,118 @@ +# +# Test Requirements: +# +# Each sample is expected to have a global variable called g_finished +# that is set to true when the sample has finish initalizing and is ready +# for a screenshot. +# +# Line Format: +# +# TestType test-name options +# +# Valid TestTypes are: +# +# small +# medium +# large +# +# options are separated by spaces. +# screenshot : take a screenshot. You can specify a time with +# screenshot(seconds) as in screenshot(4), take it at the 4 second mark. +# You can also specify more than 1 screenshot by specifying more than +# one screenshot option as in "screenshot(4), screenshot(6.5). If no time +# is specified 27.5 is used. +# +# To take a screenshot the test must have a global variable "g_client" +# that is the client plugin object from which to take a screenshot. +# +# If the sample is animated, it is expected to have a global variable +# called g_timeMult that can be set to 0 to stop the animation. All of +# its animation must be based on a global variable called g_clock, such +# that setting g_clock to the same value will always produce the same +# image. +# +# timeout(milliseconds) : Set the timeout to wait for readiness. +# Default 10000. +# +# client(client_variable_name) : Name of client variable in javascript. +# Default = "g_client" +# +# pdiff_threshold_mac(number_of_pixels_allowed) +# pdiff_threshold_win(number_of_pixels_allowed) +# pdiff_threshold_linux(number_of_pixels_allowed) +# pdiff_threshold(number_of_pixels_allowed) : Number of pixels +# allowed to be perceptually different before the test fails. +# "pdiff_threshold" specifies the threshold for all +# platforms. Platform specific versions override the +# threshold for that platform. The default threshold is 10 pixels. +# +# except(*firefox, *iexplore, *googlechrome) : Name of the browser +# environment(s) where the test should be skipped. +# Default = "" +# +# NOTE! ---------------------------------------------------------------------- +# +# Read the sample guidelines +# http://wiki.corp.google.com/twiki/bin/view/Main/ClientThreeDSampleGuidelines +# +# +medium 2d screenshot pdiff_threshold(41200) +medium animation +large animated-scene screenshot timeout(45000) pdiff_threshold(200) +large beachdemo/beachdemo screenshot timeout(120000) pdiff_threshold(15500) except(*iexplore) +medium canvas screenshot pdiff_threshold(4700) pdiff_threshold_mac(14600) +medium canvas-fonts screenshot pdiff_threshold(1100) pdiff_threshold_mac(21900) +medium canvas-texturedraw +medium checkers screenshot pdiff_threshold(1100) +medium convolution screenshot pdiff_threshold(200) +medium culling screenshot pdiff_threshold(3400) +medium debugging screenshot pdiff_threshold(2000) pdiff_threshold_mac(3000) +medium displayfps +small generate-texture screenshot pdiff_threshold(30000) except(*iexplore) +medium hellocube screenshot pdiff_threshold(1000) +medium hellocube-colors screenshot pdiff_threshold(1000) +medium helloworld screenshot pdiff_threshold(900) +medium hud-2d-overlay screenshot pdiff_threshold(11300) pdiff_threshold_win(39800) +medium instance-override screenshot pdiff_threshold(10500) +medium instancing screenshot pdiff_threshold(14300) +medium juggler screenshot +# NOTE: temporarily disabled while we investigate failures +# medium julia screenshot +small multiple-views screenshot pdiff_threshold(1900) +medium particles screenshot pdiff_threshold(35500) +medium primitives screenshot pdiff_threshold(17200) pdiff_threshold_mac(20000) +medium procedural-texture screenshot pdiff_threshold(1300) +medium render-targets screenshot pdiff_threshold(1400) +medium scatter-chart screenshot pdiff_threshold(10100) pdiff_threshold_mac(10600) +medium simple screenshot client(g_simple.client) +medium simpletexture screenshot pdiff_threshold(5100) +medium skinning screenshot pdiff_threshold(500) +medium sobel screenshot pdiff_threshold(1400) +medium stencil_example screenshot(0) screenshot(100) screenshot(7777) pdiff_threshold(4800) pdiff_threshold_win(20800) +small texturesamplers screenshot pdiff_threshold(32200) pdiff_threshold_win(37100) +medium tutorial-primitive screenshot pdiff_threshold(1200) pdiff_threshold_mac(10400) +large vertex-shader screenshot timeout(45000) pdiff_threshold(1400) except(*iexplore) +medium vertex-shader-animation screenshot pdiff_threshold(5100) +medium zsorting screenshot pdiff_threshold(39500) +# box2d-3d works in browsers but for some reason times out on some configs +#large box2d-3d/box2d-3d timeout(45000) except(*googlechrome) +large simpleviewer/simpleviewer screenshot pdiff_threshold(100) +large trends/trends timeout(30000) + +# -- tests below this line are tests for which there is a python +# function to custom run the test. As such, only the 'except' and +# pdiff_threshold options have any meaning + +small TestSampleErrorTextureSmall pdiff_threshold(2200) +small TestSampleHelloCube_TexturesSmall pdiff_threshold(5900) +small TestSampleRefreshPageLoad_Small +medium TestSampleCustomCamera pdiff_threshold(900) pdiff_threshold_win(5700) +medium TestSamplePicking +medium TestSampleRenderMode +medium TestSampleRotateModel pdiff_threshold(900) +medium TestSampleShader_Test pdiff_threshold(5800) pdiff_threshold_win(26000) +large TestSampleMultipleClientsLarge +large TestSamplePingPongLarge +# This test currently fails on IE as it considers localhost: to be a trusted +# domain. +small TestLoadTextureFromFileSmall except(*iexplore) diff --git a/o3d/tests/selenium/samples_tests.py b/o3d/tests/selenium/samples_tests.py new file mode 100644 index 0000000..7d2591e --- /dev/null +++ b/o3d/tests/selenium/samples_tests.py @@ -0,0 +1,528 @@ +#!/usr/bin/python2.4 +# Copyright 2009, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +"""Selenium tests on the o3d samples. + +Checks for javascript errors and compares screenshots +taken with reference images. + +NOTE: If you manually write a test in python (vs using the generic test) +The name of the screenshots must match the name of the test not including +the suffix. In otherwords, if your test is called TestSampleCustomCameraMedium +then your screenshots need to be named customcamera1, customcamera2 etc. + +This is so when it comes time to compare screenshots we can figure out which +reference images require a corresponding screenshot. In other words if +TestSampleCustomCameraMedium is run then we know that any reference file +named customcamera1_reference.png requires that there be a corresponding +screenshot. +""" + + +import os +import time +import selenium_utilities + + +class SampleTests(selenium_utilities.SeleniumTestCase): + """Tests a couple of samples in the o3d samples directory.""" + + # TODO: Change to correct object class when NPAPI class is exposed. + SELENIUM_OBJ_TYPE = "[object HTMLObjectElement]" + + def __init__(self, name, session, browser, test_type=None, sample_path=None, + options=None): + selenium_utilities.SeleniumTestCase.__init__( + self, name, session, browser, test_type, sample_path, options) + + def GenericTest(self): + """Generically test a sample. + + Each sample is expected to have a global variable called g_finished + which is set to true when it is finished initializing and is in a state + ready for a screenshot. + """ + self.RunGenericTest( + self.session.browserURL + "/samples/", + "(typeof(window.g_finished) != 'undefined') && " + "window.g_finished == true;", + None) + + def AssertEqualMatrix4(self, matrix1, matrix2): + """Compares two 4-by-4 matrices. + + It asserts that their entries are each very close. + Args: + matrix1: Full DOM path to first matrix in javascript. + matrix2: Full DOM path to second matrix in javascript. + """ + # Alias for the selenium session + s = self.session + for i in range(0, 4): + for j in range(0, 4): + string1 = "%s[%d][%d]" % (matrix1, i, j) + string2 = "%s[%d][%d]" % (matrix2, i, j) + a = float(s.get_eval(string1)) + b = float(s.get_eval(string2)) + self.assertTrue(abs(a - b) < 0.001) + + def TestSampleRotateModel(self): + """Tests rotatemodel.html.""" + + # Alias for the selenium session + s = self.session + s.open(s.browserURL + "/samples/rotatemodel.html") + + # wait for sample to be ready. + s.wait_for_condition("(typeof(window.g_finished) != 'undefined') && " + "window.g_finished == true;", 50000) + + # Capture screenshot + self.assertTrue(selenium_utilities.TakeScreenShot(s, self.browser, + "g_client", + "rotatemodel1")) + + # Check that local matrix is the identity + self.AssertEqualMatrix4("window.g_math.matrix4.identity()", + "window.g_sceneRoot.localMatrix") + + # TODO: s.key_press is not functioning on Chrome, so we revert + # to button-based testing of the rotation functions on this platform. + # Remove this test when chrome keyboard input works in selenium. + browser_is_chrome = self.browser == "*googlechrome" + + # Rotate slightly + if browser_is_chrome: + s.click("A") + else: + s.key_press("document.getElementById('o3d')", "a") + + # Check that rotation matrix is correct + self.AssertEqualMatrix4( + "window.g_math.matrix4.rotationZYX([0, -0.05, 0])", + "window.g_sceneRoot.localMatrix") + + # Rotate model + for unused_i in range(1, 10): + if browser_is_chrome: + s.click("W") + else: + s.key_press("document.getElementById('o3d')", "w") + + for unused_i in range(1, 5): + if browser_is_chrome: + s.click("S") + else: + s.key_press("document.getElementById('o3d')", "s") + + for unused_i in range(1, 5): + if browser_is_chrome: + s.click("A") + else: + s.key_press("document.getElementById('o3d')", "a") + + for unused_i in range(1, 10): + if browser_is_chrome: + s.click("D") + else: + s.key_press("document.getElementById('o3d')", "d") + + # Capture screenshot + self.assertTrue(selenium_utilities.TakeScreenShot(s, self.browser, + "g_client", + "rotatemodel2")) + + # Reset view + s.click("//input[@value='Reset view']") + + def TestSampleCustomCamera(self): + """Tests customcamera.html.""" + + # Alias for the selenium session + s = self.session + s.open(s.browserURL + "/samples/customcamera.html") + + # Allow a limited time for the plugin to initialize. + s.wait_for_condition("typeof(window.g_client) != 'undefined';", 10000) + + # Sanity checks. + self.assertEqual("Tutorial B4: Cameras and events", s.get_title()) + self.assertEqual("null", s.get_eval("window.undefined_symbol_xxxyyy")) + + # Try different views of the camera + time.sleep(1) + s.type("eyeX", "5") + time.sleep(1) + s.type("eyeY", "5") + time.sleep(1) + s.type("eyeZ", "5") + time.sleep(1) + s.click("btnSet") + + time.sleep(1) + s.type("eyeX", "2") + time.sleep(1) + s.type("eyeY", "3") + time.sleep(1) + s.type("eyeZ", "2") + time.sleep(1) + s.type("upX", "1") + time.sleep(1) + s.type("upY", "0") + time.sleep(1) + s.click("btnSet") + time.sleep(2) + + # Capture screenshot + self.assertTrue(selenium_utilities.TakeScreenShot(s, self.browser, + "g_client", + "customcamera1")) + + # Reset view + s.click("btnDefault") + + def TestSampleRenderMode(self): + """Tests render-mode.html.""" + + # Alias for the selenium session + s = self.session + s.open(s.browserURL + "/samples/render-mode.html") + + # Allow a limited time for the plugin to initialize. + s.wait_for_condition("typeof(window.g_client) != 'undefined';", 10000) + + # Sanity checks. + self.assertEqual("Render Mode Example.", s.get_title()) + self.assertEqual("null", s.get_eval("window.undefined_symbol_xxxyyy")) + s.wait_for_condition("window.g_client != null", 5000) + + # Wait for it to render a few frames. + s.wait_for_condition( + "window.g_framesRendered > 10", + 5000) + + # stop rendering + s.click("//input[@value='ondemand']") + + # reset frame count to 0 + s.run_script("window.g_framesRendered = 0") + + # wait 1 second + time.sleep(1) + + # check that we didn't render much. Note: This is a kind of hacky + # check because if something else (the window being covered/unconvered) + # causes the window to be refreshed this number is unpredictable. Also, + # if the window is covered we don't render so that can effect this test + # as well. The hope is since we waiting 1 second it should render 30-60 + # frames if render mode is not working. + self.assertTrue( + s.get_eval("window.g_framesRendered < 10")) + + def TestSamplePicking(self): + """Tests picking.html.""" + + # Alias for the selenium session + s = self.session + s.open(s.browserURL + "/samples/picking.html") + + # wait for sample to be ready. + s.wait_for_condition("(typeof(window.g_finished) != 'undefined') && " + "window.g_finished == true;", 50000) + + # Sanity checks. + self.assertEqual("O3D Picking Example.", s.get_title()) + + pick_info = [{"x": 189, "y": 174, "shape": "pConeShape1"}, + {"x": 191, "y": 388, "shape": "pTorusShape1"}, + {"x": 459, "y": 365, "shape": "pPipeShape1"}, + {"x": 466, "y": 406, "shape": "pCubeShape1"}] + + # if it's not working these will timeout. + for record in pick_info: + # Selenium can't really click the mouse; it can only tell JavaScript that + # the mouse has been clicked, which isn't enough to get an OS-level event + # into the plugin. So we go around the plugin and just call the event + # handler that it would have called. This means we're testing most of the + # code in the sample, but not the actual event path. + s.get_eval("window.pick({x:%d,y:%d});" % (record["x"], record["y"])) + s.wait_for_condition( + "window.g_pickInfoElem.innerHTML == '" + record["shape"] + "'", + 10000) + + def TestSampleShader_Test(self): + """Tests shader-test.html.""" + + # Alias for the selenium session + s = self.session + s.open(s.browserURL + "/samples/shader-test.html") + + # Allow a limited time for the plugin to initialize. + s.wait_for_condition("typeof(window.g_client) != 'undefined';", 20000) + + # Sanity checks. + self.assertEqual("Shader Test", s.get_title()) + self.assertEqual("null", s.get_eval("window.undefined_symbol_xxxyyy")) + + # wait for it to initialize. + s.wait_for_condition("(typeof(window.g_finished) != 'undefined') && " + "window.g_finished == true;", + 20000) + + # if they are animated we need to stop the animation and set the clock + # to some time so we get a known state. + s.run_script("g_timeMult = 0") + s.run_script("g_clock = 27.5") + + # Figure out how many options there are. + num_shaders = s.get_eval( + "window.document.getElementById('shaderSelect').length") + + # try each shader + for shader in range(0, int(num_shaders)): + # select shader + s.select("//select[@id='shaderSelect']", ("index=%d" % shader)) + # Take screenshot + self.assertTrue(selenium_utilities.TakeScreenShot( + s, self.browser, "g_client", ("shader-test%d" % shader))) + + def TestSampleErrorTextureSmall(self): + """Tests error-texture.html.""" + + # Alias for the selenium session + s = self.session + s.open(s.browserURL + "/samples/error-texture.html") + + # Allow a limited time for the plugin to initialize. + s.wait_for_condition("typeof(window.g_client) != 'undefined';", 30000) + + # Sanity checks. + self.assertEqual("Error Texture", s.get_title()) + self.assertEqual("null", s.get_eval("window.undefined_symbol_xxxyyy")) + + # Take screenshots + time.sleep(2) # helps with Vista FF screencapture + self.assertTrue(selenium_utilities.TakeScreenShot(s, self.browser, + "g_client", + "errortexture1")) + s.click("//input[@value='User Texture']") + s.wait_for_condition("(window.g_errorMsgElement.innerHTML=='-');", + 1000) + time.sleep(2) # helps with Vista FF screencapture + self.assertTrue(selenium_utilities.TakeScreenShot(s, self.browser, + "g_client", + "errortexture2")) + s.click("//input[@value='No Texture']") + s.wait_for_condition("(window.g_errorMsgElement.innerHTML==" + "'Missing texture for sampler s2d');", + 1000) + self.assertTrue(selenium_utilities.TakeScreenShot(s, self.browser, + "g_client", + "errortexture3")) + s.click("//input[@value='hide 0']") + s.wait_for_condition("(window.g_errorMsgElement.innerHTML==" + "'Missing Sampler for ParamSampler texSampler0');", + 1000) + self.assertTrue(selenium_utilities.TakeScreenShot(s, self.browser, + "g_client", + "errortexture4")) + s.click("//input[@value='hide 1']") + s.wait_for_condition("(window.g_errorMsgElement.innerHTML==" + "'Missing ParamSampler');", + 1000) + self.assertTrue(selenium_utilities.TakeScreenShot(s, self.browser, + "g_client", + "errortexture5")) + + def TestSampleMultipleClientsLarge(self): + """Tries to draw a simple example in a large number of clients.""" + + # Alias for the selenium session + s = self.session + s.open(s.browserURL + "/samples/multiple-clients.html") + + # Allow a limited time for the plugin to initialize. We spot-check the + # first and last here to make sure the page has basically loaded. Before we + # access any plugin data, we'll check each individual client. + s.wait_for_condition("typeof(window.g_clients[49]) != 'undefined';", 40000) + + # Sanity checks. + self.assertEqual("Multiple Clients", s.get_title()) + self.assertEqual("null", s.get_eval("window.undefined_symbol_xxxyyy")) + + # Wait until the entire setup is finished. + s.wait_for_condition("window.g_setupDone == true;", 5000) + + # Spot-check assets for base o3d setup: + for index in range(0, 50, 12): + client_string = ( + "window.document.getElementById('o3d%d').client" % index) + + # Make sure this client is ready for us. + s.wait_for_condition(client_string + " != null;", 1000) + s.wait_for_condition(client_string + ".root != null;", 1000) + + # There are 1 draw elements: + self.assertEqual( + "1", + s.get_eval(client_string + + ".getObjectsByClassName('o3d.DrawElement').length")) + + # There are 8 nodes in the render graph. + # 1 root render node + # 1 viewport + # 1 clear buffer + # 1 tree traversal + # 2 draw passes + # 2 StateSets + self.assertEqual( + "8", + s.get_eval(client_string + ".renderGraphRoot." + "getRenderNodesInTree().length")) + + def TestSamplePingPongLarge(self): + """Validates the start-up logic of the ping-pong sample.""" + + # Alias for the selenium session + s = self.session + s.open(s.browserURL + "/samples/pingpong/o3dPingPong.html") + + # Sanity checks. + self.assertEqual("o3dPingPong", s.get_title()) + self.assertEqual("null", s.get_eval("window.undefined_symbol_xxxyyy")) + + # Start the game + s.click("clientBanner") + + # Allow a limited time for the plugin to initialize. + s.wait_for_condition("(typeof(window.g_finished) != 'undefined') && " + "window.g_finished == true;", 10000) + + def TestSampleHelloCube_TexturesSmall(self): + """Validates loading of files from an external source.""" + + # Alias for the selenium session + s = self.session + s.open(s.browserURL + "/samples/hellocube-textures.html") + + # Sanity checks. + self.assertEqual( + "Hello Square Textures: Getting started with O3D, take 3.", + s.get_title()) + self.assertEqual("null", s.get_eval("window.undefined_symbol_xxxyyy")) + + # Allow a limited time for the plugin to initialize. + s.wait_for_condition("(typeof(window.g_finished) != 'undefined') && " + "window.g_finished == true;", 10000) + + # if they are animated we need to stop the animation and set the clock + # to some time so we get a known state. + s.run_script("g_timeMult = 0") + s.run_script("g_clock = 27.5") + + # Take screenshot + self.assertTrue(selenium_utilities.TakeScreenShot( + s, + self.browser, + "g_client", + "hellocube-textures1")) + + def TestLoadTextureFromFileSmall(self): + """Checks for improper access to local files.""" + + # Alias for the selenium session. + s = self.session + s.open(s.browserURL + "/samples/hellocube-textures.html") + + # Sanity checks. + self.assertEqual( + "Hello Square Textures: Getting started with O3D, take 3.", + s.get_title()) + self.assertEqual("null", s.get_eval("window.undefined_symbol_xxxyyy")) + + # Allow a limited time for the plugin to initialize. + s.wait_for_condition("(typeof(window.g_finished) != 'undefined') && " + "window.g_finished == true;", 10000) + + # Check that loading from a local file fails, when the page is served over + # http. + existing_image = os.path.abspath( + os.path.join(os.path.dirname(__file__), + "..", + "..", + "samples", + "assets", + "google-square.png")) + + self.assertTrue(os.path.exists(existing_image)) + s.type("url", "file://%s" % existing_image) + s.click("updateButton") + + s.wait_for_condition( + "(typeof(window.g_textureLoadDenied) != 'undefined') && " + "window.g_textureLoadDenied == true;", 10000) + + def TestSampleRefreshPageLoad_Small(self): + """Tests the behaviour of the plug-in and browser when the page is + refreshed before all of the O3D streams have loaded. + """ + + # Alias for the selenium session + s = self.session + s.open(s.browserURL + "/samples/archive-textures.html") + + # Allow a limited time for the plugin to initialize. + s.wait_for_condition("typeof(window.g_client) != 'undefined';", 10000) + + # Instruct the page to continually download content. + s.run_script("window.g_repeatDownload = true") + s.click("startLoad") + + # Wait for the browser to load the page. + s.wait_for_condition( + "(typeof(window.g_streamingStarted) != 'undefined')", 10000) + + # Refresh the page, before waiting for all of the textures to be loaded. + # This tests that the browser won't hang while processing the + # no-longer-needed streams. + s.open(s.browserURL + "/samples/archive-textures.html") + + # Allow a limited time for the plugin to initialize. + s.wait_for_condition("typeof(window.g_client) != 'undefined';", 10000) + + # Instruct the page to download the tgz file once. + s.click("startLoad") + + s.wait_for_condition("(typeof(window.g_finished) != 'undefined') && " + "window.g_finished == true;", 20000) + +if __name__ == "__main__": + pass diff --git a/o3d/tests/selenium/selenium_constants.py b/o3d/tests/selenium/selenium_constants.py new file mode 100644 index 0000000..a2aad74 --- /dev/null +++ b/o3d/tests/selenium/selenium_constants.py @@ -0,0 +1,67 @@ +#!/usr/bin/python2.4 +# Copyright 2009, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +"""Constants for the selenium scripts. + +Variables that are shared across all the selenium scripts. +""" + + +import os +import platform + +# Default path where screenshots will be stored. +DEFAULT_SCREENSHOT_PATH = os.path.join("..", + "tests", + "selenium", + "screenshots") + +# Path where reference screenshots will be stored. +# Unfortunately we need separate reference images for certain platforms +# for certain tests. +if platform.system() == "Darwin": + PLATFORM_SCREENSHOT_DIR = "reference-mac" +elif platform.system() == "Linux": + PLATFORM_SCREENSHOT_DIR = "reference-linux" +elif platform.system() == "Microsoft" or platform.system() == "Windows": + PLATFORM_SCREENSHOT_DIR = "reference-win" +else: + raise Exception, 'Platform %s not supported' % platform.system() + + + +SELENIUM_BROWSER_SET = ["*iexplore", "*firefox", "*googlechrome"] + +# Dimensions to resize window to +# on the Mac, the window has to be big enough to hold the entire o3d div +# otherwise the OpenGL context will be clipped to the size of the window +RESIZE_WIDTH = 1400 +RESIZE_HEIGHT = 1200 diff --git a/o3d/tests/selenium/selenium_utilities.py b/o3d/tests/selenium/selenium_utilities.py new file mode 100644 index 0000000..84444e1 --- /dev/null +++ b/o3d/tests/selenium/selenium_utilities.py @@ -0,0 +1,287 @@ +#!/usr/bin/python2.4 +# Copyright 2009, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +"""Utility scripts for selenium. + +A collection of utility scripts for selenium test cases to use. +""" + + +import os +import re +import time +import unittest +import gflags +import selenium_constants + + +FLAGS = gflags.FLAGS +SUFFIXES = ["small", "medium", "large"] + + +def IsValidTestType(test_type): + """Returns True if test_type is a "small", "medium" or "large".""" + return test_type.lower() in SUFFIXES + + +def IsValidSuffix(name): + """Returns True if name ends in a valid test type.""" + name = name.lower() + for suffix in SUFFIXES: + if name.endswith(suffix): + return True + return False + + +def StripTestTypeSuffix(name): + """Removes the suffix from name if it is a valid test type.""" + name_lower = name.lower() + for suffix in SUFFIXES: + if name_lower.endswith(suffix): + return name[:-len(suffix)] + return name + + +def GetArgument(string): + """Returns the value inside the first set of parentheses in a string. + + Args: + string: String in the format "identifier(args)" + + Returns: + args from string passed in. None if there were no parentheses. + """ + match = re.match("\w+\(([^)]+)\)", string) + if match: + return match.group(1) + return None + + +def TakeScreenShot(session, browser, client, filename): + """Takes a screenshot of the o3d display buffer. + + This function is the preferred way to capture an image of the plugin. + + Uses gflags: + If gflags.FLAGS.screenshots is False then screen shots will not be taken. + gflags.FLAGS.screenshotsdir must be set to the path to save screenshots in. + + Args: + session: Selenium session. + browser: Name of the browser running the test. + client: String that in javascript will return the o3d client. + filename: Name of screenshot. + Returns: + success: True on success, False on failure. + """ + # If screenshots enabled + if gflags.FLAGS.screenshots: + full_path = os.path.join(os.getcwd(), + FLAGS.screenshotsdir, + filename) + return TakeScreenShotAtPath(session, + browser, + client, + full_path) + else: + # Screenshots not enabled, return true (success). + return True + + +def TakeScreenShotAtPath(session, + browser, + client, + filename): + """Takes a screenshot of the o3d display buffer. + + This should be used by tests that need to specify exactly where to save the + image or don't want to use gflags. + + Args: + session: Selenium session. + browser: Name of the browser running the test. + client: String that in javascript will return the o3d client. + filename: Full path to screenshot to be saved. + + Returns: + success: True on success, False on failure. + """ + session.window_focus() + + # Resize window, and client area if needed. + resize_script = ["window.resizeTo(%d, %d)" % + (selenium_constants.RESIZE_WIDTH, + selenium_constants.RESIZE_HEIGHT)] + width_specification = session.get_eval( + "window.document.getElementById('o3d').style.width") + need_client_resize = width_specification.find("%") >= 0 + if need_client_resize: + resize_script += [ + "window.document.getElementById('o3d').style.width = '800px';", + "window.document.getElementById('o3d').style.height = '600px';"] + session.run_script("\n".join(resize_script)) + if need_client_resize: + session.wait_for_condition( + "window.%s.width == 800 && window.%s.height == 600" % (client, client), + 20000) + + # Execute screenshot capture code + + # Replace all backslashes with forward slashes so it is parsed correctly + # by Javascript + full_path = filename.replace("\\", "/") + + # Attempt to take a screenshot of the display buffer + eval_string = ("%s.saveScreen('%s')" % (client, full_path)) + + # Set Post render call back to take screenshot + script = ["window.g_selenium_post_render = false;", + "window.g_selenium_save_screen_result = false;", + "var frameCount = 0;", + "%s.setPostRenderCallback(function() {" % client, + " ++frameCount;", + " if (frameCount >= 3) {", + " %s.clearPostRenderCallback();" % client, + " window.g_selenium_save_screen_result = %s;" % eval_string, + " window.g_selenium_post_render = true;", + " } else {", + " %s.render()" % client, + " }", + "})", + "%s.render()" % client] + session.run_script("\n".join(script)) + # Wait for screenshot to be taken. + session.wait_for_condition("window.g_selenium_post_render", 20000) + + # Get result + success = session.get_eval("window.g_selenium_save_screen_result") + + if success == u"true": + print "Saved screenshot %s." % full_path + return True + + return False + + +class SeleniumTestCase(unittest.TestCase): + """Wrapper for TestCase for selenium.""" + + def __init__(self, name, session, browser, test_type=None, sample_path=None, + options=None): + """Constructor for SampleTests. + + Args: + name: Name of unit test. + session: Selenium session. + browser: Name of browser. + test_type: Type of test ("small", "medium", "large") + sample_path: Path to test. + options: list of option strings. + """ + + unittest.TestCase.__init__(self, name) + self.session = session + self.browser = browser + self.test_type = test_type + self.sample_path = sample_path + self.options = options + + def shortDescription(self): + """override unittest.TestCase shortDescription for our own descriptions.""" + if self.sample_path: + return "Testing: " + self.sample_path + ".html" + else: + return unittest.TestCase.shortDescription(self) + + def RunGenericTest(self, base_path, ready_condition, assertion): + """Runs a generic test. + + Args: + base_path: path for sample. + ready_condition: condition to check in javascript to know sample is ready. + assertion: javascript to check equals "true" + + Assumes self.sample_path is a path to the html page to load and that + samples.options is an array of option strings. + + If the sample is animated, it is expected to have a global variable + called g_timeMult that can be set to 0 to stop the animation. All of its + animation must be based on a global variable called g_clock, such that + setting g_clock to the same value will always produce the same image. + + Finally, each sample is expected to have a global variable called + g_client which is the o3d client object for that sample. This is + used to take a screenshot. + """ + screenshots = [] + timeout = 10000 + client = "g_client" + + self.assertTrue(self.test_type in ["small", "medium", "large"]) + + # parse options + for option in self.options: + if option.startswith("screenshot"): + clock = GetArgument(option) + if clock is None: + clock = "27.5" + screenshots.append(clock) + elif option.startswith("timeout"): + timeout = GetArgument(option) + self.assertTrue(not timeout is None) + elif option.startswith("client"): + client = GetArgument(option) + self.assertTrue(not client is None) + + url = base_path + self.sample_path + ".html" + + # load the sample. + self.session.open(url) + + # wait for it to initialize. + self.session.wait_for_condition(ready_condition, timeout) + + if assertion: + self.assertEqual("true", self.session.get_eval(assertion)) + + # take a screenshot. + screenshot_id = 1 + for clock in screenshots: + # if they are animated we need to stop the animation and set the clock + # to some time so we get a known state. + self.session.run_script("g_timeMult = 0") + self.session.run_script("g_clock = " + clock) + + # take a screenshot. + screenshot = self.sample_path.replace("/", "_") + str(screenshot_id) + self.assertTrue(TakeScreenShot(self.session, self.browser, + client, screenshot)) + screenshot_id += 1 diff --git a/o3d/tests/selenium/tests/assets/archive.o3dtgz b/o3d/tests/selenium/tests/assets/archive.o3dtgz Binary files differnew file mode 100644 index 0000000..c482299 --- /dev/null +++ b/o3d/tests/selenium/tests/assets/archive.o3dtgz diff --git a/o3d/tests/selenium/tests/base-test.html b/o3d/tests/selenium/tests/base-test.html new file mode 100644 index 0000000..1683983 --- /dev/null +++ b/o3d/tests/selenium/tests/base-test.html @@ -0,0 +1,81 @@ +<!-- +Copyright 2009, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title> +Base Test +</title> +</head> +<body> +<h1>Base Test</h1> +This tests base.js. +<br/> + +<!-- Start of O3D plugin --> +<div id="o3d" style="width: 32px; height: 32px;"></div> +<!-- End of O3D plugin --> + +<script type="text/javascript" + src="../../../samples/o3djs/base.js"></script> +<script type="text/javascript"> + +o3djs.require('o3djs.test'); +o3djs.require('o3djs.util'); + +g_suite = {}; + +g_suite.testIsArrayWorksInBrowserForV8Arrays = function() { + g_test.assertTrue(o3djs.base.isArray(g_plugin.eval('[1, 2, 3]'))); +}; + +g_suite.testIsArrayWorksForBrowser = function() { + g_test.assertFalse(o3djs.base.isArray(undefined)); + g_test.assertFalse(o3djs.base.isArray(7)); + g_test.assertTrue(o3djs.base.isArray([1, 2, 3])); +}; + +function initStep2(clientElements) { + g_test = o3djs.test; + g_plugin = clientElements[0]; + g_testResult = g_test.runTests(g_suite); +}; + +window.onload = function() { + o3djs.util.makeClients(initStep2); +}; + +</script> +</body> +</html> diff --git a/o3d/tests/selenium/tests/culling-zsort-test.html b/o3d/tests/selenium/tests/culling-zsort-test.html new file mode 100644 index 0000000..097b30d --- /dev/null +++ b/o3d/tests/selenium/tests/culling-zsort-test.html @@ -0,0 +1,459 @@ +<!-- +Copyright 2009, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + +<!-- +O3D Culling and ZSorting Test. + +Make sure things off screen get culled. +--> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title> +Culling and ZSorting Test. +</title> +<!-- Include sample javascript library functions--> +<script type="text/javascript" src="../../../samples/o3djs/base.js"></script> + +<!-- Our javascript code --> +<script type="text/javascript"> +o3djs.require('o3djs.util'); +o3djs.require('o3djs.math'); +o3djs.require('o3djs.rendergraph'); +o3djs.require('o3djs.primitives'); + +// Events +// init() once the page has finished loading. +// unload() when the page is unloaded. +window.onload = init; +window.onunload= unload; + +// global variables +var g_timeMult = 1.0; +var g_framesRendered = 0; +var g_o3d; +var g_math; +var g_client; +var g_viewInfos = []; +var g_pack; +var g_o3d_width; // width of our client area +var g_o3d_height; // height of our client area +var g_clock = 0; +var g_totalTransformsElement; +var g_transformsProcessedElement; +var g_transformsCulledElement; +var g_totalDrawElementsElement; +var g_drawElementsProcessedElement; +var g_drawElementsCulledElement; +var g_drawElementsRenderedElement; +var g_primitivesRenderedElement; +var GROUPS_ACROSS = 4; +var UNITS_ACROSS_GROUP = 3; +var TOTAL_ACROSS = GROUPS_ACROSS * UNITS_ACROSS_GROUP; +var HALF_WIDTH = TOTAL_ACROSS * 0.5; +var UNIT_SPACING = 100; + +/** + * Returns the path of where the file is located + * with the trailing slash + */ +function getCurrentPath() { + var path = window.location.href; + var index = path.lastIndexOf('/'); + return path.substring(0, index + 1); +} + +function createInstances(pack, shape) { + // now make a grid of transforms and put a teapot instance on each one + for (var g = 0; g < GROUPS_ACROSS; g++) { + for (var h = 0; h < GROUPS_ACROSS; h++) { + for (var i = 0; i < GROUPS_ACROSS; i++) { + var groupTransform = pack.createObject('Transform'); + groupTransform.parent = g_client.root; + groupTransform.cull = true; + var boundingBox = g_o3d.BoundingBox([0, 0, 0], + [0, 0, 0]); + groupTransform.localMatrix = g_math.matrix4.translation([ + (g * UNITS_ACROSS_GROUP - HALF_WIDTH) * UNIT_SPACING, + (h * UNITS_ACROSS_GROUP - HALF_WIDTH) * UNIT_SPACING, + (i * UNITS_ACROSS_GROUP - HALF_WIDTH) * UNIT_SPACING]); + for (var x = 0; x < UNITS_ACROSS_GROUP; x++) { + for (var y = 0; y < UNITS_ACROSS_GROUP; y++) { + for (var z = 0; z < UNITS_ACROSS_GROUP; z++) { + var transform = pack.createObject('Transform'); + transform.parent = groupTransform; + transform.cull = true; + transform.addShape(shape); + var elements = shape.elements; + var box = elements[0].boundingBox; + for (var ee = 1; ee < elements.length; ee++) { + box = box.add(elements[ee].boundingBox); + } + transform.boundingBox = box; + transform.localMatrix = g_math.matrix4.translation([ + (x - UNITS_ACROSS_GROUP * 0.5) * UNIT_SPACING, + (y - UNITS_ACROSS_GROUP * 0.5) * UNIT_SPACING, + (z - UNITS_ACROSS_GROUP * 0.5) * UNIT_SPACING]); + transform.createParam('colorMult', 'ParamFloat4').value = [ + (g * UNITS_ACROSS_GROUP + x) * (1 / TOTAL_ACROSS), + (h * UNITS_ACROSS_GROUP + y) * (1 / TOTAL_ACROSS), + (i * UNITS_ACROSS_GROUP + z) * (1 / TOTAL_ACROSS), + 1]; + var box = transform.boundingBox.mul(transform.localMatrix); + boundingBox = boundingBox.add(box); + } + } + } + groupTransform.boundingBox = boundingBox; + } + } + } +} + +/** + * Creates the client area. + */ +function init() { + o3djs.util.makeClients(initStep2); +} + +/** + * Initializes O3D and creates one shape. + * @param {Array} clientElements Array of o3d object elements. + */ +function initStep2(clientElements) { + // Initializes global variables and libraries. + var o3d = clientElements[0]; + g_o3d = o3d.o3d; + g_math = o3djs.math; + g_client = o3d.client; + + g_totalTransformsElement = + document.getElementById('totalTransforms'); + g_transformsProcessedElement = + document.getElementById('transformsProcessed'); + g_transformsCulledElement = + document.getElementById('transformsCulled'); + g_totalDrawElementsElement = + document.getElementById('totalDrawElements'); + g_drawElementsProcessedElement = + document.getElementById('drawElementsProcessed'); + g_drawElementsCulledElement = + document.getElementById('drawElementsCulled'); + g_drawElementsRenderedElement = + document.getElementById('drawElementsRendered'); + g_primitivesRenderedElement = + document.getElementById('primitivesRendered'); + + // Get the width and height of our client area. We will need this to create + // a projection matrix. + g_o3d_width = o3d.clientWidth; + g_o3d_height = o3d.clientHeight; + + // Creates a pack to manage our resources/assets + g_pack = g_client.createPack(); + + // Create the render graph for a view. + for (var yy = 0; yy < 2; yy++) { + for (var xx = 0; xx < 2; xx++) { + var viewInfo; + var ii = yy * 2 + xx; + if (xx == 0 && yy == 0) { + viewInfo = o3djs.rendergraph.createBasicView( + g_pack, + g_client.root, + g_client.renderGraphRoot, + [0.5, 0.5, 0.5, 1], + 0, + [0, 0, 0.5, 0.5]); + + } else { + viewInfo = o3djs.rendergraph.createExtraView( + g_viewInfos[0], + [xx * 0.5, yy * 0.5, 0.5, 0.5], // top-right + [0.5, 0.2 + xx * 0.5, 0.7 - yy * 0.5, 1.0]); + } + g_viewInfos[ii] = viewInfo; + + // Create our projection matrix, with a vertical field of view of 45 + // degrees a near clipping plane of 0.1 and far clipping plane of 100. + viewInfo.drawContext.projection = g_math.matrix4.perspective( + 45 * 3.14159 / 180, + g_o3d_width / g_o3d_height, + 0.1, + 10000); + } + } + + /* Load the effect for our sphere from our file. + Effects, stored in a hidden textarea for simplicity, contain the + functions that define the vertex and pixel shaders used by our shape. + + Here, we calculate phong illumination in our vertex shader and pass the + resultant color to our pixel shader, which does nothing except output its + given (input) color. + */ + var defaultEffect = g_pack.createObject('Effect'); + defaultEffect.loadFromFXString(document.getElementById('shader').value); + + // Create a Material for the effect. + var material = g_pack.createObject('Material'); + + // Apply our effect to this material. + material.effect = defaultEffect; + + // Set the material's drawList + material.drawList = g_viewInfos[0].zOrderedDrawList; + + // create params the effect needs on the material. + defaultEffect.createUniformParameters(material); + + // Light position + var light_pos_param = material.getParam('light_pos'); + light_pos_param.value = [1000, 1000, 0]; + + // Phong components of the light source + var light_ambient_param = material.getParam('light_ambient'); + var light_diffuse_param = material.getParam('light_diffuse'); + var light_specular_param = material.getParam('light_specular'); + + // White ambient light + light_ambient_param.value = [0.1, 0.1, 0.1, 1]; + // Reddish diffuse light + light_diffuse_param.value = [1, 1, 1, 1]; + // White specular light + light_specular_param.value = [0.5, 0.5, 0.5, 1]; + + // Shininess of the material (for specular lighting) + var shininess_param = material.getParam('shininess'); + shininess_param.value = 5.0; + + // Position of the camera. + // (should be the same as the 'eye' position given below) + var camera_pos_param = material.getParam('camera_pos'); + // Camera is at (0, 0, 3). + camera_pos_param.value = [0, 0, 3]; + + // Create 2 spheres. + var shape1 = o3djs.primitives.createSphere( + g_pack, + material, + 20, + 10, + 12, + g_math.matrix4.translation([-25, 0, 0])); + + var shape2 = o3djs.primitives.createSphere( + g_pack, + material, + 20, + 10, + 12, + g_math.matrix4.translation([25, 0, 0])); + + // Create a shape and move the 2 sphere primitives to the same shape. + var shape = g_pack.createObject('Shape'); + shape1.elements[0].owner = shape; + shape2.elements[0].owner = shape; + g_pack.removeObject(shape1); + g_pack.removeObject(shape2); + var elements = shape.elements; + elements[0].cull = true; + elements[1].cull = true; + + createInstances(g_pack, shape); + + g_totalDrawElementsElement.innerHTML = g_client.getObjectsByClassName( + 'o3d.DrawElement').length; + g_totalTransformsElement.innerHTML = g_client.getObjectsByClassName( + 'o3d.Transform').length; + + // Setup an onrender callback for animation. + g_client.setRenderCallback(onrender); +} + +// spin the camera. +function onrender(renderEvent) { + g_framesRendered++; + // Get the number of seconds since the last render. + var elapsedTime = renderEvent.elapsedTime; + g_clock += elapsedTime * g_timeMult; + + for (var vv = 0; vv < 4; vv++) { + var clock = g_clock * (vv * 0.1 + 1); + var x = Math.sin(clock * 0.1) * 400; + var z = Math.cos(clock * 0.1) * 400; + var y = Math.sin(clock * 0.2) * 400; + + g_viewInfos[vv].drawContext.view = g_math.matrix4.lookAt( + [x, y, z], + [0, 0, 0], + [0, 1, 0]); + } + + g_transformsProcessedElement.innerHTML = renderEvent.transformsProcessed; + g_transformsCulledElement.innerHTML = renderEvent.transformsCulled; + g_drawElementsProcessedElement.innerHTML = renderEvent.drawElementsProcessed; + g_drawElementsCulledElement.innerHTML = renderEvent.drawElementsCulled; + g_drawElementsRenderedElement.innerHTML = renderEvent.drawElementsRendered; + g_primitivesRenderedElement.innerHTML = renderEvent.primitivesRendered; +} + +/** + * Remove any callbacks so they don't get called after the page has unloaded. + */ +function unload() { + if (g_client) { + g_client.cleanup(); + } +} +</script> +</head> +<body> +<h1>Culling and ZSort Test</h1> +Objects off screen should get culled and nothing in the front should zbuffer out +stuff in the back. +<br/> +<!-- Start of O3D plugin --> +<div id="o3d" style="width: 800px; height: 600px;"></div> +<!-- End of O3D plugin --> +<table> +<tr><td>Total Transforms:</td><td><span id="totalTransforms">-</span></td></tr> +<tr><td>Transforms Processed:</td><td><span id="transformsProcessed">-</span></td></tr> +<tr><td>Transforms Culled:</td><td><span id="transformsCulled">-</span></td></tr> +<tr><td>Total DrawElements:</td><td><span id="totalDrawElements">-</span></td></tr> +<tr><td>DrawElements Processed:</td><td><span id="drawElementsProcessed">-</span></td></tr> +<tr><td>DrawElements Culled:</td><td><span id="drawElementsCulled">-</span></td></tr> +<tr><td>DrawElements Rendered:</td><td><span id="drawElementsRendered">-</span></td></tr> +<tr><td>Primitives Rendered:</td><td><span id="primitivesRendered">-</span></td></tr> +</table> +<!-- Don't render the textarea --> +<div style="display:none"> +<textarea id="shader" name="fx" cols="80" rows="20"> +// The 4x4 world view projection matrix. +float4x4 worldViewProjection : WorldViewProjection; +float4x4 worldInverseTranspose : WorldInverseTranspose; +float4x4 world : World; + +// positions of the light and camera +float3 light_pos; +float3 camera_pos; + +// lighting components of the light source +float4 light_ambient; +float4 light_diffuse; +float4 light_specular; + +// shininess of the material. (for specular lighting) +float shininess; + +float4 colorMult; + +// input parameters for our vertex shader +struct a2v { + float4 pos : POSITION; + float3 normal : NORMAL; + float4 col : COLOR; +}; + +// input parameters for our pixel shader +// also the output parameters for our vertex shader +struct v2f { + float4 pos : POSITION; + float4 pos2 : TEXCOORD0; + float3 norm : TEXCOORD1; + float3 light : TEXCOORD2; + float4 col : COLOR; +}; + +/** + * vsMain - our vertex shader + * + * @param IN.pos Position vector of vertex + * @param IN.normal Normal of vertex + * @param IN.col Color of vertex + */ +v2f vsMain(a2v IN) { + /** + * We use the standard phong illumination equation here. + * We restrict (clamp) the dot products so that we + * don't get any negative values. + * All vectors are normalized for proper calculations. + * + * The output color is the summation of the + * ambient, diffuse, and specular contributions. + * + * Note that we have to transform each vertex and normal + * by the view projection matrix first. + */ + v2f OUT; + + OUT.pos = mul(IN.pos, worldViewProjection); + OUT.pos2 = OUT.pos; + OUT.norm = mul(float4(IN.normal, 0), worldInverseTranspose).xyz; + OUT.light = light_pos - mul(IN.pos, world).xyz; + OUT.col = IN.col; + return OUT; +} +/** + * psMain - pixel shader + * + * @param IN.pos Position vector of vertex + * @param IN.col Color of vertex + */ +float4 psMain(v2f IN): COLOR { + float3 light = normalize(IN.light); + float3 normal = normalize(IN.norm); + float3 litR = normalize(2 * dot(light, normal) * normal - light); + float3 v = normalize(mul(float4(camera_pos, 1), + worldViewProjection).xyz - IN.pos2.xyz); + + // use lit function to calculate phong shading + float4 phong_coeff = lit(dot(normal, light), dot(litR, v), shininess); + float4 ambient = light_ambient * phong_coeff.x * IN.col; + float4 diffuse = light_diffuse * phong_coeff.y * IN.col; + float4 specular = light_specular * phong_coeff.z * IN.col; + + return float4(((ambient + diffuse) * colorMult + specular).xyz, 0.5); +} + +// Here we tell our effect file *which* functions are +// our vertex and pixel shaders. + +// #o3d VertexShaderEntryPoint vsMain +// #o3d PixelShaderEntryPoint psMain +// #o3d MatrixLoadOrder RowMajor +</textarea> +</div> +</body> +</html> diff --git a/o3d/tests/selenium/tests/drawshapes.html b/o3d/tests/selenium/tests/drawshapes.html new file mode 100644 index 0000000..c25901b --- /dev/null +++ b/o3d/tests/selenium/tests/drawshapes.html @@ -0,0 +1,395 @@ +<!-- +Copyright 2009, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + +<!-- +O3D Shape Stress Test + +This test generates a number of shapes that display on an empty o3d canvas. +We assign each shape a pixel shader that colors the shape via a parameter. +The color is set randomly. +--> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title> +Drawshape stress test for O3D +</title> +<script type="text/javascript" src="../../../samples/o3djs/base.js"></script> +<script type="text/javascript"> +o3djs.require('o3djs.util'); +o3djs.require('o3djs.math'); +o3djs.require('o3djs.rendergraph'); + +// Events +// Run the init() function once the page has finished loading. +// and unload() when the page is unloaded. +window.onload = init; +window.onunload= unload; + +// global variables +var g_o3d; +var g_math; +var g_client; +var g_viewInfo; +var g_packEffect; +var g_packShapes; +var g_material; +var g_parentTransform; + +// Variables for computing FPS +var FPS_FRAMES_FOR_SAMPLE = 10; // number of frames to average for FPS. +var g_totalTime = 0.0; // total time spent for last N frames. +var g_timeTable = []; // elapsed time for last N frames. +var g_timeTableCursor = 0; + +/** + * Returns a random double between -1 and 1. + */ +function getRandom() { + return (Math.random() - 0.5) * 2; +} + +/** + * Creates a shape with the given effect + * @param {Material} material material which our shape will use. + * @param {Shape::PrimitiveType} primitiveType the shape's primitive type + */ +function createShape(material, primitiveType) { + // First, create a 'shape' and 'primitive' to store the our geometry. + var myShape = g_packShapes.createObject('Shape'); + var myPrimitive = g_packShapes.createObject('Primitive'); + var myBank = g_packShapes.createObject('StreamBank'); + myPrimitive.owner = myShape; + myPrimitive.streamBank = myBank; + + // Apply our material to this primitive. + myPrimitive.material = material; + + myPrimitive.primitiveType = primitiveType; + myPrimitive.numberPrimitives = 1; // 1 primitive. + + if (primitiveType == g_o3d.Primitive.TRIANGLELIST) { + // Triangle list + myPrimitive.numberVertices = 3; // 3 vertices in total + + // Create a javascript array that gives the coordinates of each of the + // 3 corners (vertices) of the triangle. + + var vertsArray = [ + // Triangle + getRandom(), getRandom(), 0, + getRandom(), getRandom(), 0, + getRandom(), getRandom(), 0 + ]; + + // Check if vertices are oriented clockwise. + // If not, we re-orient them. + // This is done by checking the determinant. + var determinant = + vertsArray[0] * vertsArray[4] + + vertsArray[3] * vertsArray[7] + + vertsArray[6] * vertsArray[1] - + vertsArray[3] * vertsArray[1] - + vertsArray[6] * vertsArray[4] - + vertsArray[0] * vertsArray[7]; + + // vertices oriented wrongly. + if (determinant < 0) { + // swap vertices to reorient. + var tmpVertX = vertsArray[0]; + var tmpVertY = vertsArray[1]; + vertsArray[0] = vertsArray[3]; + vertsArray[1] = vertsArray[4]; + vertsArray[3] = tmpVertX; + vertsArray[4] = tmpVertY; + } + + // The index array defines the order of the vertices we want to draw. + // Here we tell the renderer that + // Triangle 1 is created from vertices 0, 1 and 2. + // Triangle 2 is created from vertices 3, 4 and 5. + var indicesArray = [ + 0, 1, 2 + ]; + } else if (primitiveType == g_o3d.Primitive.LINELIST) { + // Line list + myPrimitive.numberVertices = 2; // 2 vertices in total + + var vertsArray = [ + // Line + getRandom(), getRandom(), 0, + getRandom(), getRandom(), 0 + ]; + + var indicesArray = [ + 0, 1 + ]; + } + + // These next few lines take our javascript arrays and load them into some + // 'buffers' where the 3D hardware can find them. We have to do this because + // the 3D hardware can't 'see' javascript data until it is in a buffer. + var vertexBuffer = g_packShapes.createObject('VertexBuffer'); + var field = vertexBuffer.createField('FloatField', 3); + vertexBuffer.set(vertsArray); + + var indexBuffer = g_packShapes.createObject('IndexBuffer'); + indexBuffer.set(indicesArray); + + // Now we associate these 'buffers' of data with our primitive so that it can + // access the data. + myBank.setVertexStream(g_o3d.Stream.POSITION, + 0, + field, + 0); + myPrimitive.indexBuffer = indexBuffer; + + // Create a shapeColor parameter directly on the primitive so we don't have + // to create multiple materials. + var shapeColorParam = myPrimitive.createParam('shapeColor', 'ParamFloat4'); + shapeColorParam.value = [Math.random(), Math.random(), Math.random(), 1]; + + // We now attach our shape to the transform. + g_parentTransform.addShape(myShape); + + // Lastly we generate the draw elements. + g_parentTransform.createDrawElements(g_packShapes, null); +} + +/** + * Creates the client area. + */ +function init() { + o3djs.util.makeClients(initStep2); +} + +/** + * Initializes O3D and loads the effect. + * @param {Array} clientElements Array of o3d object elements. + */ +function initStep2(clientElements) { + // Initialize global variables and libraries. + var o3d = clientElements[0]; + g_o3d = o3d.o3d; + g_math = o3djs.math; + g_client = o3d.client; + + var pack = g_client.createPack(); + + // Create the render graph for a view. + g_viewInfo = o3djs.rendergraph.createBasicView( + pack, + g_client.root, + g_client.renderGraphRoot); + + // Create packs to manage our resources/assets + g_packEffect = g_client.createPack(); + g_packShapes = g_client.createPack(); + + // Load the effect for the shapes from the textarea and associate it + // with the pack. + var effect = g_packEffect.createObject('Effect'); + var fxString = document.getElementById('fx').value; + effect.loadFromFXString(fxString); + + // Create a material. + g_material = g_packEffect.createObject('Material'); + + // Set the material's drawList + g_material.drawList = g_viewInfo.performanceDrawList; + + // Apply our effect to this material. + g_material.effect = effect; + effect.createUniformParameters(g_material); + + // Create a parent transform + g_parentTransform = + g_packShapes.createObject('Transform'); + g_parentTransform.parent = g_client.root; + + // Initialize the FPS elapsed time history table. + for (var tt = 0; tt < FPS_FRAMES_FOR_SAMPLE; tt++ ) { + g_timeTable[tt] = 0.0; + } + + // Set our render callback to display stats. + g_client.setRenderCallback(onrender); +} + +/** + * Creates several shapes in the scene and renders them. + */ +function createShapes(numShapes, primitiveType) { + // Creates the shapes using the default effect. + for (var i = 0; i < numShapes; i++) + createShape(g_material, primitiveType); +} + +/** + * Destroys all the shapes that we have created. + */ +function destroyShapes() { + // Remove references + g_parentTransform.parent = null; + g_packShapes.destroy(); + + // Re-create parent transform and pack + g_packShapes = g_client.createPack(); + g_parentTransform = + g_packShapes.createObject('Transform'); + g_parentTransform.parent = g_client.root; +} + +/** + * Frees unreferenced objects by destroying the packs on page unload. + */ +function unload() { + g_packEffect.destroy(); + g_packShapes.destroy(); +} + +// Updates statistics. +// This function executes on each frame. +function onrender(renderEvent) { + if (window.g_client) { + document.getElementById('clientObjectCount').innerHTML = + g_client.getObjectsByClassName('o3d.ObjectBase').length; + // Update FPS + // Get the number of seconds since the last render. + var elapsedTime = renderEvent.elapsedTime; + + // Keep the total time for the last N frames. + g_totalTime += elapsedTime - g_timeTable[g_timeTableCursor]; + + // Save off the elapsed time for this frame so we can subtract it later. + g_timeTable[g_timeTableCursor] = elapsedTime; + + // Wrap the place to store the next time sample. + g_timeTableCursor++; + if (g_timeTableCursor == FPS_FRAMES_FOR_SAMPLE) { + g_timeTableCursor = 0; + } + + // Print the average frame rate for the last N frames as well as the + // instantaneous frame rate. + document.getElementById('fps').innerHTML = "" + + Math.floor((1.0 / (g_totalTime / FPS_FRAMES_FOR_SAMPLE)) + 0.5) + + " : " + Math.floor(1.0 / elapsedTime + 0.5); + + + } +} + +</script> +</head> +<body> +<h1>Draw shapes stress test</h1> +This is a shape drawing stress test for o3d. +<br/> +Enter in the number of shapes to create and click the +appropriate shape type button to render the shapes. +<br/> +<!-- Start of O3D plugin --> +<div id="o3d" style="width: 600px; height: 600px;"></div> +<!-- End of O3D plugin --> +<br/> +<form action="#" method="get" name="defaultForm"> + Render <input type="text" name="numShapes" value="3"> + <input type="button" name="btnTri" value="Triangles" + onClick="createShapes( + document.defaultForm.numShapes.value, + g_o3d.Primitive.TRIANGLELIST)"> + <input type="button" name="btnLines" value="Lines" + onClick="createShapes( + document.defaultForm.numShapes.value, + g_o3d.Primitive.LINELIST)"> + <br/> + <input type="button" name="btnClear" value="Clear" + onClick="destroyShapes()"> +</form> +<table border="0" summary="O3D statistics"> + <tr> + <td style="font-weight:bold">Client Object Count:</td> + <td id="clientObjectCount">0</td> + </tr> + <tr> + <td style="font-weight:bold; color:red">FPS:</td> + <td id="fps">0</td> + </tr> +</table> +<!-- Don't render the textarea --> +<div style="display:none"> +<!-- Start of effect --> +<textarea id="fx" name="fx" cols="80" rows="20"> + // This is the color of the triangle. + // We bind this to a javascript variable shapeColorParam + // to modify its value dynamically + float4 shapeColor : FLOAT4; + + // input parameters for our vertex shader + struct a2v { + float4 pos : POSITION; + }; + + // input parameters for our pixel shader + struct v2f { + float4 pos : POSITION; + }; + + /** + * Our vertex shader does nothing but returns the position of the vertex. + * (which is unused eventually) + */ + v2f vsMain(a2v IN) { + v2f OUT; + OUT.pos = IN.pos; + return OUT; + } + + /* Our pixel shader returns the color which is assigned dynamically. + */ + float4 psMain(v2f IN): COLOR { + return shapeColor; + } + + // Here we tell our effect file *which* functions are + // our vertex and pixel shaders. + + // #o3d VertexShaderEntryPoint vsMain + // #o3d PixelShaderEntryPoint psMain + // #o3d MatrixLoadOrder RowMajor +</textarea> +<!-- End of effect --> +</div> +</body> +</html> diff --git a/o3d/tests/selenium/tests/effect-import-test.html b/o3d/tests/selenium/tests/effect-import-test.html new file mode 100644 index 0000000..6a2515f --- /dev/null +++ b/o3d/tests/selenium/tests/effect-import-test.html @@ -0,0 +1,154 @@ +<!-- +Copyright 2009, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + +<!-- +Test that when importing a file Effects get shared. +--> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title> +Effect Import Test +</title> +<!-- Include sample javascript library functions--> +<script type="text/javascript" src="../../../samples/o3djs/base.js"></script> + +<!-- Our javascript code --> +<script type="text/javascript"> +o3djs.require('o3djs.util'); +o3djs.require('o3djs.rendergraph'); +o3djs.require('o3djs.camera'); +o3djs.require('o3djs.pack'); +o3djs.require('o3djs.scene'); + +// Events +// init() once the page has finished loading. +window.onload = init; + +// global variables +var g_o3d; +var g_client; +var g_viewInfo; +var g_testResult; +var g_pack; + +/** + * Loads a model into the transform graph and generates its corresponding entry + * in the render graph when it is done loading. + * @param {!o3d.Pack} pack Pack to load model into. + * @param {string} fileName filename of the model. + * @param {!o3d.Transform} parent parent node in the transform graph to + * which to load the model into. + */ +function loadModel(pack, fileName, parent) { + // Get our full path to the model + var modelPath = o3djs.util.getCurrentURI() + fileName; + + // Load the file given the full path, and call the callback function + // when its done loading. + o3djs.scene.loadScene(g_client, pack, parent, modelPath, callback); + + /** + * Our callback is called once the model has been loaded into memory + * from the web or locally. + * @param {!o3d.Pack} pack The pack that was passed in above. + * @param {!o3d.Transform} parent The parent that was passed in above. + * @param {*} exception null if loading succeeded. + */ + function callback(pack, parent, exception) { + if (exception) { + alert('Could not load: ' + fileName + '\n' + exception); + return; + } + // Get a cameraInfo (an object with a view and projection matrix) + // using our javascript library function + var cameraInfo = o3djs.camera.getViewAndProjectionFromCameras( + parent, + g_client.width, + g_client.height); + + // Copy the camera info from the file the draw context. + g_viewInfo.drawContext.view = cameraInfo.view; + g_viewInfo.drawContext.projection = cameraInfo.projection; + + // Generate draw elements and setup material draw lists. + o3djs.pack.preparePack(pack, g_viewInfo); + + var effects = g_client.getObjectsByClassName('o3d.Effect'); + g_testResult = effects.length == 1; + } +} + +/** + * Creates the client area. + */ +function init() { + o3djs.util.makeClients(initStep2); +} + +/** + * Initializes O3D and loads the model into the transform graph. + * @param {Array} clientElements Array of o3d object elements. + */ +function initStep2(clientElements) { + // Initializes global variables and libraries. + var o3d = clientElements[0]; + g_o3d = o3d.o3d; + g_client = o3d.client; + + // Creates a pack to manage our resources/assets + g_pack = g_client.createPack(); + + // Create the render graph. + g_viewInfo = o3djs.rendergraph.createBasicView( + g_pack, + g_client.root, + g_client.renderGraphRoot); + + // Load the model into the transform graph. + loadModel(g_pack, + '../../../samples/assets/seven_shapes.o3dtgz', + g_client.root); +} +</script> +</head> +<body> +<h1>Effect Import Test</h1> +<br/> +Test that when importing a file Effects get shared. +<br/> +<!-- Start of O3D plugin --> +<div id="o3d" style="width: 800px; height: 600px;"></div> +<!-- End of O3D plugin --> +</body> +</html> diff --git a/o3d/tests/selenium/tests/event-test.html b/o3d/tests/selenium/tests/event-test.html new file mode 100644 index 0000000..57c160c --- /dev/null +++ b/o3d/tests/selenium/tests/event-test.html @@ -0,0 +1,284 @@ +<!-- +Copyright 2009, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title> +Event Test +</title> +</head> +<body> +<h1>Event Test</h1> +This tests the event-handler functions in the event.js library. +<br/> +<script type="text/javascript" + src="../../../samples/o3djs/base.js"></script> +<script type="text/javascript"> + +o3djs.require('o3djs.event'); +o3djs.require('o3djs.test'); + +var g_event = {}; + +function FakeClient() { +}; + +FakeClient.prototype.getCallbacks = function() { + this.callbacks = this.callbacks || []; + return this.callbacks; +}; + +FakeClient.prototype.setEventCallback = function(type, callback) { + this.getCallbacks()[type] = callback; +}; + +FakeClient.prototype.clearEventCallback = function(type) { + this.getCallbacks()[type] = null; +}; + +FakeClient.prototype.handleEvent = function(type, event) { + var callback = this.getCallbacks()[type]; + if (callback) { + g_test.assertTrue(typeof(callback) == 'function'); + callback(event); + } +}; + +function FakePlugin() { + this.client = new FakeClient(); +} + +FakePlugin.prototype.handleEvent = function(type, event) { + this.client.handleEvent(type, event); +}; + +var g_a; +function incA(event) { + g_test.assertTrue(event != null); + g_test.assertTrue(event == g_event); + ++g_a; +} + +var incAAsEventListener = { + handleEvent: incA +}; + +var g_b; +function incB(event) { + g_test.assertTrue(event != null); + g_test.assertTrue(event == g_event); + ++g_b; +} + +var g_suite = {}; + +g_suite.testSimpleHandler = function() { + var fakePlugin = new FakePlugin; + g_a = 0; + g_b = 0; + o3djs.event.addEventListener(fakePlugin, 'click', incA); + g_test.assertEquals(0, g_a); + g_test.assertEquals(0, g_b); + fakePlugin.handleEvent('click', g_event); + g_test.assertEquals(1, g_a); + g_test.assertEquals(0, g_b); +} + +g_suite.testMultipleHandlers = function() { + var fakePlugin = new FakePlugin; + g_a = 0; + g_b = 0; + o3djs.event.addEventListener(fakePlugin, 'click', incA); + o3djs.event.addEventListener(fakePlugin, 'click', incB); + g_test.assertEquals(0, g_a); + g_test.assertEquals(0, g_b); + fakePlugin.handleEvent('click', g_event); + g_test.assertEquals(1, g_a); + g_test.assertEquals(1, g_b); +} + +g_suite.testAddingHandlerIsIdempotent = function() { + var fakePlugin = new FakePlugin; + g_a = 0; + g_b = 0; + o3djs.event.addEventListener(fakePlugin, 'click', incA); + o3djs.event.addEventListener(fakePlugin, 'click', incA); + g_test.assertEquals(0, g_a); + g_test.assertEquals(0, g_b); + fakePlugin.handleEvent('click', g_event); + g_test.assertEquals(1, g_a); + g_test.assertEquals(0, g_b); +} + +g_suite.testAddingAndRemovingHandlers = function() { + var fakePlugin = new FakePlugin; + g_a = 0; + g_b = 0; + o3djs.event.addEventListener(fakePlugin, 'click', incA); + o3djs.event.addEventListener(fakePlugin, 'click', incB); + g_test.assertEquals(0, g_a); + g_test.assertEquals(0, g_b); + fakePlugin.handleEvent('click', g_event); + g_test.assertEquals(1, g_a); + g_test.assertEquals(1, g_b); + // Check that it's repeatable. + fakePlugin.handleEvent('click', g_event); + g_test.assertEquals(2, g_a); + g_test.assertEquals(2, g_b); + o3djs.event.removeEventListener(fakePlugin, 'click', incA); + fakePlugin.handleEvent('click', g_event); + g_test.assertEquals(2, g_a); + g_test.assertEquals(3, g_b); + o3djs.event.removeEventListener(fakePlugin, 'click', incB); + fakePlugin.handleEvent('click', g_event); + g_test.assertEquals(2, g_a); + g_test.assertEquals(3, g_b); + // Check that removing in the opposite order works too. + var fakePlugin = new FakePlugin; + g_a = 0; + g_b = 0; + o3djs.event.addEventListener(fakePlugin, 'click', incA); + o3djs.event.addEventListener(fakePlugin, 'click', incB); + g_test.assertEquals(0, g_a); + g_test.assertEquals(0, g_b); + fakePlugin.handleEvent('click', g_event); + g_test.assertEquals(1, g_a); + g_test.assertEquals(1, g_b); + // Check that it's repeatable. + fakePlugin.handleEvent('click', g_event); + g_test.assertEquals(2, g_a); + g_test.assertEquals(2, g_b); + o3djs.event.removeEventListener(fakePlugin, 'click', incB); + fakePlugin.handleEvent('click', g_event); + g_test.assertEquals(3, g_a); + g_test.assertEquals(2, g_b); + o3djs.event.removeEventListener(fakePlugin, 'click', incA); + fakePlugin.handleEvent('click', g_event); + g_test.assertEquals(3, g_a); + g_test.assertEquals(2, g_b); +} + +g_suite.testRemovingHandlerIsIdempotent = function() { + var fakePlugin = new FakePlugin; + g_a = 0; + g_b = 0; + o3djs.event.addEventListener(fakePlugin, 'click', incA); + o3djs.event.addEventListener(fakePlugin, 'click', incA); + g_test.assertEquals(0, g_a); + g_test.assertEquals(0, g_b); + fakePlugin.handleEvent('click', g_event); + g_test.assertEquals(1, g_a); + g_test.assertEquals(0, g_b); + o3djs.event.removeEventListener(fakePlugin, 'click', incA); + fakePlugin.handleEvent('click', g_event); + g_test.assertEquals(1, g_a); + g_test.assertEquals(0, g_b); + o3djs.event.removeEventListener(fakePlugin, 'click', incA); + fakePlugin.handleEvent('click', g_event); + g_test.assertEquals(1, g_a); + g_test.assertEquals(0, g_b); +} + +g_suite.testEventListenerIsLikeFunction = function() { + var fakePlugin = new FakePlugin; + g_a = 0; + g_b = 0; + o3djs.event.addEventListener(fakePlugin, 'click', incA); + o3djs.event.addEventListener(fakePlugin, 'click', incAAsEventListener); + g_test.assertEquals(0, g_a); + g_test.assertEquals(0, g_b); + fakePlugin.handleEvent('click', g_event); + g_test.assertEquals(2, g_a); + g_test.assertEquals(0, g_b); + o3djs.event.removeEventListener(fakePlugin, 'click', incA); + fakePlugin.handleEvent('click', g_event); + g_test.assertEquals(3, g_a); + g_test.assertEquals(0, g_b); + o3djs.event.removeEventListener(fakePlugin, 'click', incA); + fakePlugin.handleEvent('click', g_event); + g_test.assertEquals(4, g_a); + g_test.assertEquals(0, g_b); + o3djs.event.removeEventListener(fakePlugin, 'click', + incAAsEventListener); + fakePlugin.handleEvent('click', g_event); + g_test.assertEquals(4, g_a); + g_test.assertEquals(0, g_b); +} + +g_suite.testMultipleDifferentEvents = function() { + var fakePlugin = new FakePlugin; + g_a = 0; + g_b = 0; + o3djs.event.addEventListener(fakePlugin, 'click', incA); + o3djs.event.addEventListener(fakePlugin, 'mousedown', incB); + g_test.assertEquals(0, g_a); + g_test.assertEquals(0, g_b); + fakePlugin.handleEvent('click', g_event); + g_test.assertEquals(1, g_a); + g_test.assertEquals(0, g_b); + fakePlugin.handleEvent('mousedown', g_event); + g_test.assertEquals(1, g_a); + g_test.assertEquals(1, g_b); + o3djs.event.removeEventListener(fakePlugin, 'mousedown', incA); + o3djs.event.removeEventListener(fakePlugin, 'click', incB); + fakePlugin.handleEvent('click', g_event); + g_test.assertEquals(2, g_a); + g_test.assertEquals(1, g_b); + fakePlugin.handleEvent('mousedown', g_event); + g_test.assertEquals(2, g_a); + g_test.assertEquals(2, g_b); + o3djs.event.removeEventListener(fakePlugin, 'click', incA); + fakePlugin.handleEvent('click', g_event); + g_test.assertEquals(2, g_a); + g_test.assertEquals(2, g_b); + fakePlugin.handleEvent('mousedown', g_event); + g_test.assertEquals(2, g_a); + g_test.assertEquals(3, g_b); + o3djs.event.removeEventListener(fakePlugin, 'mousedown', incB); + fakePlugin.handleEvent('click', g_event); + g_test.assertEquals(2, g_a); + g_test.assertEquals(3, g_b); + fakePlugin.handleEvent('mousedown', g_event); + g_test.assertEquals(2, g_a); + g_test.assertEquals(3, g_b); +} + +window.onload = function() { + window.g_test = o3djs.test; + window.g_testResult = g_test.runTests(g_suite); +}; + +</script> +</body> +</html> diff --git a/o3d/tests/selenium/tests/features-test.html b/o3d/tests/selenium/tests/features-test.html new file mode 100644 index 0000000..22cc131 --- /dev/null +++ b/o3d/tests/selenium/tests/features-test.html @@ -0,0 +1,157 @@ +<!-- +Copyright 2009, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + +<!-- +Features Test + +Make sure when features are not requested you can not use them and when +they are requested you can use them. +--> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title> +Features Test. +</title> +<!-- Include sample javascript library functions--> +<script type="text/javascript" src="../../../samples/o3djs/base.js"></script> + +<!-- Our javascript code --> +<script type="text/javascript"> +o3djs.require('o3djs.util'); +o3djs.require('o3djs.rendergraph'); + +// Events +// init() once the page has finished loading. +// unload() when the page is unloaded. +window.onload = init; + +// Events +// init() once the page has finished loading. +window.onload = init; + +// global variables +var g_client; +var g_pack; +var g_testResult; + +/** + * Checks the client.lastError is empty or not after calling a function. + * @param {!o3d.Client} client The client to use. + * @param {boolean} expectError True if we expect an error. + * @param {!function(): void} func Function to call. + * @return {boolean} True if error matched expectations. + */ +function checkForError(client, expectError, func) { + client.clearLastError(); + func(); + var haveError = client.lastError.length > 0; + return haveError == expectError; +} + +/** + * Creates a buffer with the requested number of elements. + * @param {!o3d.Pack} pack Pack to create buffer in. + * @param {number} numElements Number of elements to create. + */ +function createBuffer(pack, numElements) { + var buffer = pack.createObject('VertexBuffer'); + var field = buffer.createField('FloatField', 1); + buffer.allocateElements(numElements); +} + +/** + * Checks that features error or are available based on if they were requested. + * + * @param {!Element} o3dElement The o3dElement for the O3D object. + * @param {boolean} expectError True if we expect errors when using the + * features. + * @return {boolean} True if checks succeeded. + */ +function checkFeatures(o3dElement, expectError) { + var o3d = o3dElement.o3d; + var client = o3dElement.client; + client.clearErrorCallback(); + var pack = client.createPack(); + // A list of functions that each create something that require a feature. + var functions = [ + function() { pack.createTexture2D(32, 32, o3d.Texture.R32F, 1, false); }, + function() { pack.createTexture2D(32, 32, o3d.Texture.ABGR16F, 1, false); }, + function() { pack.createTexture2D(32, 32, o3d.Texture.ABGR32F, 1, false); }, + function() { createBuffer(pack, 65535); }, + ]; + + for (var ii = 0; ii < functions.length; ++ii) { + if (!checkForError(client, expectError, functions[ii])) { + return false; + } + } + + return true; +} + +/** + * Creates the client areas. + */ +function init() { + o3djs.util.makeClients(initStep2); // no features requested. +} + +/** + * Initializes O3D and loads the model into the transform graph. + * @param {Array} clientElements Array of o3d object elements. + */ +function initStep2(clientElements) { + g_testResult = checkFeatures(clientElements[0], true) && + checkFeatures(clientElements[1], false); + + document.getElementById('result').innerHTML = g_testResult ? + '<font color="green">success</font>' : + '<font color="red">failure</font>'; +} +</script> +</head> +<body> +<h1>Features Test</h1> +Make sure when features are not requested you can not use them and when +they are requested you can use them. +<br/> +<br/> +<div>Result: <span id="result"></span></div> +<!-- Start of O3D plugin --> +<div id="o3d1" style="width: 100px; height: 100px;"></div> +<br/> +<div id="o3d2" o3d_features="FloatingPointTextures,LargeGeometry" style="width: 100px; height: 100px;"></div> +<!-- End of O3D plugin --> +</body> +</html> diff --git a/o3d/tests/selenium/tests/init-status-test.html b/o3d/tests/selenium/tests/init-status-test.html new file mode 100644 index 0000000..08b9eb2 --- /dev/null +++ b/o3d/tests/selenium/tests/init-status-test.html @@ -0,0 +1,117 @@ +<!-- +Copyright 2009, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + +<!-- +Init Status Test + +Check we get the expected result if the plugin does not start. +--> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title> +Init Status Test. +</title> +<!-- Include sample javascript library functions--> +<script type="text/javascript" src="../../../samples/o3djs/base.js"></script> + +<!-- Our javascript code --> +<script type="text/javascript"> +o3djs.require('o3djs.util'); +o3djs.require('o3djs.rendergraph'); + +// Events +// init() once the page has finished loading. +window.onload = init; + +// global variables +var g_client; +var g_pack; +var g_testResult; + +/** + * Creates the client areas. + */ +function init() { + setTimeout(failed, 2000); + o3djs.util.makeClients(initStep2, 'InitStatus=3'); +} + +/** + * Initializes O3D. + * @param {Array} clientElements Array of o3d object elements. + */ +function initStep2(clientElements) { + g_testResult = false; +} + +/** + * Called if makeClients failed. + */ +function failed () { + var tag = 'div'; + var id = '^o3d'; + var msg = + 'We are terribly sorry but it appears your graphics card is not ' + + 'able to run o3d. We are working on a solution.'; + var elements = document.getElementsByTagName(tag); + for (var ee = 0; ee < elements.length; ++ee) { + var element = elements[ee]; + if (element.id && element.id.match(id)) { + var innerHTML = element.innerHTML; + g_testResult = (innerHTML.indexOf(msg) >= 0); + document.getElementById('result').innerHTML = g_testResult ? + '<font color="green">success</font>' : + '<font color="red">failure</font>'; + return; + } + } +} + +</script> +</head> +<body> +<h1>Init Status Test</h1> + +Check we get the expected result if the plugin does not start. +<br/> +<br/> +<div>Result: <span id="result"></span></div> +<br/> +Note: You should see "We are terribly sorry..." below. +<!-- Start of O3D plugin --> +<div id="o3d" style="width: 600px; height: 600px;"></div> +<br/> +<!-- End of O3D plugin --> +</body> +</html> diff --git a/o3d/tests/selenium/tests/math-test.html b/o3d/tests/selenium/tests/math-test.html new file mode 100644 index 0000000..981c673 --- /dev/null +++ b/o3d/tests/selenium/tests/math-test.html @@ -0,0 +1,861 @@ +<!-- +Copyright 2009, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title> +Math Test +</title> +</head> +<body> +<h1>Math Test</h1> +This tests the math utility library. +<br/> +<script type="text/javascript" + src="../../../samples/o3djs/base.js"></script> +<script type="text/javascript"> + +o3djs.require('o3djs.math'); +o3djs.require('o3djs.test'); + +var isChrome = navigator.userAgent.indexOf('Chrome') != -1; +var isSafari = !isChrome && navigator.userAgent.indexOf('Safari') != -1; +var isFirefox = navigator.userAgent.indexOf('Firefox') != -1; +var isInternetExplorer = navigator.userAgent.indexOf('Internet Explorer' != -1); + +var g_suite = {}; + +g_suite.testDegToRad = function() { + g_test.assertEquals(Math.PI, g_math.degToRad(180)); +}; + +g_suite.testRadToDeg = function() { + g_test.assertEquals(180, g_math.radToDeg(Math.PI)); +}; + +g_suite.testScalarLerp = function() { + g_test.assertEquals(3, g_math.lerpScalar(2, 6, .25)); +}; + +g_suite.testModClamp = function() { + g_test.assertEquals(0.5, g_math.modClamp(2.5, 2.0)); + g_test.assertEquals(0.5, g_math.modClamp(6.5, 2.0)); + g_test.assertEquals(3.0, g_math.modClamp(3.0, 2.0, 2.5)); + g_test.assertEquals(1.5, g_math.modClamp(-0.5, 2.0)); + g_test.assertEquals(0.5, g_math.modClamp(-3.5, 2.0)); +} + +g_suite.testLerpCircular = function() { + g_test.assertEquals(30, g_math.lerpCircular(0, 100, 0.3, 300)); + g_test.assertEquals(270, g_math.lerpCircular(0, 200, 0.3, 300)); + g_test.assertEquals(0, g_math.lerpCircular(0, 300, 1, 300)); +} + +g_suite.testLerpRadian = function() { + g_test.assertEquals(0.3, g_math.lerpRadian(0, 1, 0.3)); + g_test.assertEquals(Math.PI * 2 - 0.3, + g_math.lerpRadian(0, Math.PI * 2 - 1, 0.3)); + g_test.assertEquals(0, g_math.lerpRadian(0, Math.PI * 2, 1)); +} + +g_suite.testVectorNegative = function() { + g_test.assertArrayEquals([0, 6, 7], g_math.negativeVector([0, -6, -7])); +}; + +g_suite.testVectorCopy = function() { + var v = [0, 6, 7]; + var u = g_math.copyVector(v); + g_test.assertArrayEquals(u, v); + g_test.assertFalse(u == v); +}; + +g_suite.testVectorAdd = function() { + g_test.assertArrayEquals([0, 6, 7], g_math.addVector([1, 2, 3], [-1, 4, 4])); + g_test.assertArrayEquals([1, -1, -1], g_math.addVector([0, 0, 0], + [1, -1, -1])); +}; + +g_suite.testVectorSub = function() { + g_test.assertArrayEquals([2, -2, -1, 4], + g_math.subVector([1, 2, 3, 4], [-1, 4, 4, 0])); +}; + +g_suite.testVectorLerp = function() { + g_test.assertArrayEquals([0.5, 2.5, 3.25, 3], + g_math.lerpVector([1, 2, 3, 4], [-1, 4, 4, 0], 0.25)); +} + +g_suite.testVectorMul = function() { + g_test.assertArrayEquals([2, 4, 6], g_math.mulScalarVector(2, [1, 2, 3])); + g_test.assertArrayEquals([2, 4, 6], g_math.mulVectorScalar([1, 2, 3], 2)); +} + +g_suite.testVectorDiv = function() { + g_test.assertArrayEquals([0.5, 1, 1.5, 2], + g_math.divVectorScalar([1, 2, 3, 4], 2)); +}; + +g_suite.testDotProduct = function() { + g_test.assertEquals(19, g_math.dot([-1, 4, 4], [1, 2, 3])); +}; + +g_suite.testLength = function() { + g_test.assertEquals(13, g_math.length([5, 12])); +}; + +g_suite.testLengthSquared = function() { + g_test.assertEquals(169, g_math.lengthSquared([5, 12])); +}; + +g_suite.testDistance = function() { + g_test.assertEquals(13, g_math.distance([1, 1], [6, 13])); +}; + +g_suite.testDistanceSquared = function() { + g_test.assertEquals(169, g_math.distanceSquared([1, 1], [6, 13])); +}; + +g_suite.testNormalize = function() { + g_test.assertEquals(1, g_math.length(g_math.normalize([1, 2, 3]))); + g_test.assertEquals(0, + g_math.length(g_math.cross(g_math.normalize([1, 2, 3]), [1, 2, 3]))); +}; + +g_suite.testCrossProduct = function() { + var u = [-1, 4, 4]; + var v = [1, 2, 3]; + g_test.assertArrayEquals([4, 7, -6], g_math.cross(u, v)); + g_test.assertEquals(0, g_math.dot(g_math.cross(u, v), u)); + g_test.assertEquals(0, g_math.dot(g_math.cross(u, v), v)); +}; + + +var A = [[1, 2, 3], [2, -5, 1], [-1, 5, 3], [1, 4, 2]]; +var B = [[0, 1, -1], [1, -1, 3], [2, 1, 2], [0, -1, 4]]; + +g_suite.testMatrixNegative = function() { + g_test.assertArrayEquals( + [[-1, -2, -3], [-2, 5, -1], [1, -5, -3], [-1, -4, -2]], + g_math.negativeMatrix(A)); +}; + +g_suite.testMatrixCopy = function() { + var M = g_math.copyMatrix(A); + g_test.assertArrayEquals(A, M); + g_test.assertFalse(A == M); +}; + +g_suite.testMatrixAdd = function() { + g_test.assertArrayEquals([[1, 3, 2], [3, -6, 4], [1, 6, 5], [1, 3, 6]], + g_math.addMatrix(A, B)); +}; + +g_suite.testMatrixSub = function() { + g_test.assertArrayEquals([[1, 1, 4], [1, -4, -2], [-3, 4, 1], [1, 5, -2]], + g_math.subMatrix(A, B)); +}; + +g_suite.testMatrixLerp = function() { + g_test.assertArrayEquals( + [[0.75, 1.75, 2], + [1.75, -4, 1.5], + [-0.25, 4, 2.75], + [0.75, 2.75, 2.5]], g_math.lerpMatrix(A, B, .25)); +}; + +g_suite.testMulScalarMatrix = function() { + g_test.assertArrayEquals([[2, 4, 6], [4, -10, 2], [-2, 10, 6], [2, 8, 4]], + g_math.mulMatrixScalar(A, 2)); + g_test.assertArrayEquals([[2, 4, 6], [4, -10, 2], [-2, 10, 6], [2, 8, 4]], + g_math.mulScalarMatrix(2, A)); +}; + +g_suite.testMatrixDiv = function() { + g_test.assertArrayEquals( + [[0.5, 1, 1.5], [1, -2.5, 0.5], [-0.5, 2.5, 1.5], [0.5, 2, 1]], + g_math.divMatrixScalar(A, 2)); +}; + +// The square root of the sum of squares of the entries of a matrix. +function frobeniusNorm(a) { + return Math.sqrt(g_math.trace(g_math.mulMatrixMatrix( + g_math.transpose(a), a))); +}; + +// The sum of squares of entries of the difference between two matrices. +function matrixDiff(a,b) { + return frobeniusNorm(g_math.subMatrix(a,b)); +}; + +// Multiplies a matrix by its inverse and checks that it is not +// too different from the identity. (With floating-point error, exact +// equality is too much to ask). +function inverseTest(a) { + g_test.assertTrue(matrixDiff(g_math.mulMatrixMatrix(a, g_math.inverse(a)), + g_math.identity(a.length)) < 0.001); + g_test.assertTrue(matrixDiff(g_math.mulMatrixMatrix(g_math.inverse(a), a), + g_math.identity(a.length)) < 0.001); +}; + +g_suite.testTranspose = function() { + g_test.assertArrayEquals([[1, 2, -1, 1], [2, -5, 5, 4], [3, 1, 3, 2]], + g_math.transpose([[1, 2, 3], [2, -5, 1], [-1, 5, 3], [1, 4, 2]])); +}; + +g_suite.testTrace = function() { + g_test.assertEquals(6, g_math.trace([ + [1, 2, 3, 4], + [1, -2, 1, 1], + [1, 1, 0, -1], + [1,2,-1,7]])); +}; + +g_suite.testIdentity = function() { + g_test.assertArrayEquals([[1, 0], [0, 1]], g_math.identity(2)); + g_test.assertArrayEquals([[1, 0, 0], [0, 1, 0], [0, 0, 1]], + g_math.identity(3)); +}; + +g_suite.testDeterminant2 = function() { + g_test.assertEquals(-2, g_math.det([[1, 2], [3, 4]])); +}; + +g_suite.testDeterminant3 = function() { + g_test.assertEquals(10, g_math.det([[1, 2, 3], [1, -2, 1], [1, 1, 0]])); +}; + +g_suite.testDeterminant4 = function() { + g_test.assertEquals(28, g_math.det([ + [1, 2, 3, 4], + [1, -2, 1, 1], + [1, 1, 0, -1], + [1, 2, -1, 0]])); +}; + +g_suite.testDeterminant5 = function() { + g_test.assertEquals(-120.00, + g_math.det([ + [2, 5,-1, 2, 1], + [1, 2,-1, 3, 2], + [1, 3, 4, 7, -3], + [1, -1, 1, 2, -4], + [0, 1, 0, 1, 0]])); +}; + +g_suite.testMatrixInversion2 = function() { + inverseTest([[1, 2], [3, 4]]); +}; + +g_suite.testMatrixInversion3 = function() { + inverseTest([[1, 2, 3], [1, -2, 1], [1, 1, 0]]); +}; + +g_suite.testMatrixInversion4 = function() { + inverseTest([[1, 2, 3, 4], [1, -2, 1, 1], + [1, 1, 0, -1], [1, 2, -1, 0]]); +}; + +g_suite.testMatrixInversion5 = function() { + inverseTest([ + [2, 5, -1, 2, 1], + [1, 2, -1, 3, 2], + [1, 3, 4, 7, -3], + [1, -1, 1, 2, -4], + [0, 1, 0, 1, 0]]); +}; + +var S = [[1, 2, 3, 0], [2, -5, 1, 1]]; +var T = [[1, 2, 3], [2, -5, 1], [-1, 5, 3], [1, 4, 2]]; +var U = [[2, 5, -1, 2], [1, 2, -1, 3], [1, 3, 4, 7]]; + +g_suite.testRowMajorMulMatrixMatrix = function() { + g_test.assertArrayEquals( + [[7, 18, 9, 29], [0, 3, 7, -4], [6, 14, 8, 34], [8, 19, 3, 28]], + g_math.rowMajor.mulMatrixMatrix(T, U)); + g_test.assertArrayEquals([[2, 7, 14], [-8, 38, 6]], + g_math.rowMajor.mulMatrixMatrix(S, T)); +}; + +g_suite.testColumnMajorMulMatrixMatrix = function() { + g_test.assertArrayEquals([[7, 18, 9, 29], + [0, 3, 7, -4], + [6, 14, 8, 34], + [8, 19, 3, 28]], + g_math.columnMajor.mulMatrixMatrix(U, T)); + g_test.assertArrayEquals([[2, 7, 14], [-8, 38, 6]], + g_math.columnMajor.mulMatrixMatrix(T, S)); +}; + +g_suite.testRowMajorMulMatrixMatrix2 = function() { + g_test.assertArrayEquals([[5, -2], [9, -2]], + g_math.rowMajor.mulMatrixMatrix2([[1, 2], [3, 4]], [[-1, 2], [3,-2]])); +}; + +g_suite.testColumnMajorMulMatrixMatrix2 = function() { + g_test.assertArrayEquals([[5, 6], [-3, -2]], + g_math.columnMajor.mulMatrixMatrix2([[1, 2], [3, 4]], [[-1, 2], [3,-2]])); +}; + +g_suite.testRowMajorMulMatrixMatrix3 = function() { + g_test.assertArrayEquals([[6, 0, 10], [14, 8, 42], [-4, 12, 20]], + g_math.rowMajor.mulMatrixMatrix3( + [[1, 2, 1], [3, 4, 5], [-1, -3, 4]], + [[-1, 2, 4], [3, -2, 0], [1, 2, 6]])); +}; + +g_suite.testColumnMajorMulMatrixMatrix3 = function() { + g_test.assertArrayEquals([[1, -6, 25], [-3, -2, -7], [1, -8, 35]], + g_math.columnMajor.mulMatrixMatrix3( + [[1, 2, 1], [3, 4, 5], [-1, -3, 4]], + [[-1, 2, 4], [3, -2, 0], [1, 2, 6]])); +}; + +g_suite.testRowMajorMatrixMatrix4 = function() { + g_test.assertArrayEquals([ + [8, 5, 9, 7], + [12, 3, 43, 33], + [0, 22, 18, 1], + [14, 10, 14, 9]], + g_math.rowMajor.mulMatrixMatrix4( + [[1, 2, 1, 1], [3, 4, 5, -1], [-1, -3, 4, 2], [1, 3, 2, 2]], + [[-1, 2, 4, 4], [3, -2, 0, 1], [1, 2, 6, 3], [2, 5, -1, -2]])); +}; + +g_suite.testColumnMajorMatrixMatrix4 = function() { + g_test.assertArrayEquals([ + [5, 6, 33, 13], + [-2, 1, -5, 7], + [4, 1, 41, 17], + [16, 21, 19, -9]], + g_math.columnMajor.mulMatrixMatrix4( + [[1, 2, 1, 1], [3, 4, 5, -1], [-1, -3, 4, 2], [1, 3, 2, 2]], + [[-1, 2, 4, 4], [3, -2, 0, 1], [1, 2, 6, 3], [2, 5, -1, -2]])); +}; + +g_suite.testRowMajorMulMatrixVector = function() { + g_test.assertArrayEquals([5, 9, 0, 1], + g_math.rowMajor.mulMatrixVector(T, [1, -1, 2])); +}; + +g_suite.testColumnMajorMulMatrixVector = function() { + g_test.assertArrayEquals([-2, 21, 10], + g_math.columnMajor.mulMatrixVector(T, [1, -1, 2, 1])); +}; + +g_suite.testRowMajorMulVectorMatrix = function() { + g_test.assertArrayEquals([-2, 21, 10], + g_math.rowMajor.mulVectorMatrix([1, -1, 2, 1], T)); +}; + +g_suite.testColumnMajorMulVectorMatrix = function() { + g_test.assertArrayEquals([5, 9, 0, 1], + g_math.columnMajor.mulVectorMatrix([1, -1, 2], T)); +}; + +g_suite.testMulVectorVector = function() { + g_test.assertArrayEquals([-1, 0, 6, -8], + g_math.mulVectorVector([1, 2, 3, 4], + [-1, 0, 2, -2])); +}; + +g_suite.testOrthonormalize = function() { + var W = g_math.orthonormalize([[1, 2, -1], [1, -2, 0], [2, 4, 1]]); + g_test.assertTrue(matrixDiff(g_math.mulMatrixMatrix(W, g_math.transpose(W)), + g_math.identity(3)) < 0.001); + g_test.assertTrue(matrixDiff(g_math.mulMatrixMatrix(g_math.transpose(W), W), + g_math.identity(3)) < 0.001); + g_test.assertTrue(matrixDiff( + g_math.orthonormalize([[1.01, -.01, 0], [0, 1.01, .01], [0, -0.1, 1.01]]), + g_math.identity(3)) < 0.1); +}; + +function dehomogenize(v) { + return [v[0] / v[3], v[1] / v[3], v[2] / v[3]]; +}; + +function homogenize(v) { + return [v[0], v[1], v[2], 1]; +}; + +function push0(v) { + return [v[0], v[1], v[2], 0]; +}; + +function pop0(v) { + return [v[0], v[1], v[2]]; +}; + +g_suite.testPerspective = function() { + var angle = 1; + var aspect = 16 / 9; + var zNear = 3; + var zFar = 10; + + var P = g_math.matrix4.perspective(angle, aspect, zNear, zFar); + + // Points on the near clipping plane should get sent to points on the plane + // z = 0, and points on the far clipping plane should get sent to points on + // the plane z = 1. + sendTest(P, [0, 0, -zNear], [0, 0, 0]); + sendTest(P, [0, 0, -zFar], [0, 0, 1]); + + // The right edge of the near rectangular face of the frustum should get sent + // to the point [1, 0, 0] + sendTest(P, [zNear * aspect * Math.tan(angle / 2), 0, -zNear], [1, 0, 0]); + + // The top edge of the near rectangular face of the frustum should get sent + // to the point [0, 1, 0] + sendTest(P, [0, zNear * Math.tan(angle / 2), -zNear], [0, 1, 0]); +}; + +g_suite.testOrthographic = function() { + var left = 3; + var right = 5; + var bottom = 4; + var top = 6; + var near = 2; + var far = 100; + + var P = g_math.matrix4.orthographic(left, right, bottom, top, near, far); + + // Points on the near face of the viewing box should get sent to the plane + // z = 0. + sendTest(P, [left, bottom, -near], [-1, -1, 0]); + sendTest(P, [right, bottom, -near], [1, -1, 0]); + sendTest(P, [left, top, -near], [-1, 1, 0]); + + // Points on the far face of the viewing box should get sent to the plane + // z = 1. + sendTest(P, [left, bottom, -far], [-1, -1, 1]); +}; + +g_suite.testLookAt = function() { + var eye = [1, 2, 4]; + var target = [1, -1, 3]; + var up = [0, 1, 1]; + var v = []; + + var M = g_math.matrix4.lookAt(eye, target, up); + + var U = g_math.matrix4.getUpper3x3(M); + g_test.assertTrue( + Math.abs(g_math.det(g_math.matrix4.getUpper3x3(M)) - 1) < 0.0001); + + // M rotation component should be orthogonal. + g_test.assertTrue(matrixDiff(g_math.mulMatrixMatrix(U, g_math.transpose(U)), + g_math.identity(3)) < 0.001); + + // M should send the eye to the origin. + sendTest(M, eye, [0, 0, 0]); + + // M should send (target-eye) to point in the -z direction. + v = g_math.mulVectorMatrix(push0(g_math.subVector(target, eye)), M); + g_test.assertTrue(Math.abs(v[0]) < 0.0001); + g_test.assertTrue(Math.abs(v[1]) < 0.0001); + g_test.assertTrue(v[2] < 0); + + // M should send up into the zy plane with positive y. + v = g_math.mulMatrixVector(M, push0(up)); + g_test.assertTrue(Math.abs(v[0]) < 0.0001); + g_test.assertTrue(v[1] > 0); + + // Arguments with four entries should be accepted, so all the following should + // be equal. + var lookats = [ + g_math.matrix4.lookAt(homogenize(eye), homogenize(target), push0(up)), + g_math.matrix4.lookAt(eye, homogenize(target), push0(up)), + g_math.matrix4.lookAt(homogenize(eye), target, push0(up)), + g_math.matrix4.lookAt(eye, target, push0(up)), + g_math.matrix4.lookAt(homogenize(eye), homogenize(target), up), + g_math.matrix4.lookAt(eye, homogenize(target), up), + g_math.matrix4.lookAt(homogenize(eye), target, up), + g_math.matrix4.lookAt(eye, target, up) + ]; + + for (var i = 0; i < 7; ++i) + g_test.assertArrayEquals(lookats[i], lookats[i + 1]); +}; + +g_suite.testGetAndSetUpper3x3 = function() { + var a = [[1, 2, 1, 1], [3, 4, 5, -1], [-1, -3, 4, 2], [1, 3, 2, 2]]; + var b = [[10, 11, 12], [13, 14, 15], [16, 17, 18]]; + var r = g_math.matrix4.setUpper3x3(a, b); + + g_test.assertTrue(r == a); + g_test.assertArrayEquals([[10, 11, 12, 1], + [13, 14, 15, -1], + [16, 17, 18, 2], + [1, 3, 2, 2]], a); + + g_test.assertArrayEquals(g_math.matrix4.getUpper3x3(a), b); +}; + +g_suite.testGetAndSetTranslation = function() { + var a = [[1, 2, 1, 1], [3, 4, 5, -1], [-1, -3, 4, 2], [1, 3, 2, 2]]; + var t = [-4, -5, -6]; + var r = g_math.matrix4.setTranslation(a, t); + + g_test.assertTrue(r == a); + g_test.assertArrayEquals([[1, 2, 1, 1], + [3, 4, 5, -1], + [-1, -3, 4, 2], + [-4, -5, -6, 1]], a); + g_test.assertArrayEquals(g_math.matrix4.getTranslation(a), t); +}; + +g_suite.testTransformPoint = function() { + var m = [[1, 2, 1, 1], [3, 4, 5, -1], [-1, -3, 4, 2], [1, 3, 2, 2]]; + var v3 = [1, 2, 3]; + + sendTest(m, v3, g_math.matrix4.transformPoint(m, v3)); +}; + +g_suite.testTransformVector4 = function() { + var m = [[1, 2, 1, 1], [3, 4, 5, -1], [-1, -3, 4, 2], [1, 3, 2, 2]]; + var v4 = [1, 2, 3, 4]; + var v3 = dehomogenize(v4); + + sendTest(m, v3, dehomogenize(g_math.matrix4.transformVector4(m, v4))); +}; + +g_suite.testTransformDirection = function() { + // It is important that the last coordinate of the first three vectors of m be + // 0, so that m is parallel-preserving. + var m = [[1, 2, 1, 0], [3, 4, 5, 0], [-1, -3, 4, 0], [1, 3, 2, 2]]; + var v3 = [1, 2, 3]; + + directionSendTest(m, v3, g_math.matrix4.transformDirection(m, v3)); +}; + +g_suite.testTransformNormal = function() { + // It is important that the last coordinate of the first three vectors of m be + // 0, so that m is parallel-preserving. + var m = [[1, 2, 1, 0], [3, 4, 5, 0], [-1, -3, 4, 0], [1, 3, 2, 2]]; + var v3 = [1, 2, 3]; + + // Transform the direction by the inverse transpose and make sure we get the + // same answer. + var a = g_math.matrix4.transformDirection( + g_math.inverse(g_math.transpose(m)), v3); + var b = g_math.matrix4.transformNormal(m, v3); + + g_test.assertTrue(g_math.distance(a, b) < 0.001); +}; + +g_suite.testMatrix4Identity = function() { + g_test.assertArrayEquals([[1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [0, 0, 0, 1]], g_math.matrix4.identity()); +}; + +g_suite.testRowAndColumn = function() { + var a = [[1, 2, 1, 1], [3, 4, 5, -1], [-1, -3, 4, 2]]; + + g_test.assertArrayEquals([-1, -3, 4, 2], g_math.rowMajor.row(a, 2)); + g_test.assertArrayEquals([2, 4, -3], g_math.rowMajor.column(a, 1)); + + g_test.assertArrayEquals([2, 4, -3], g_math.columnMajor.row(a, 1)); + g_test.assertArrayEquals([-1, -3, 4, 2], g_math.columnMajor.column(a, 2)); +}; + +g_suite.testComposition = function() { + var b = [[1, 2, 1, 1], [3, 4, 5, -1], [-1, -3, 4, 2], [1, 3, 2, 2]]; + var a = g_math.matrix4.identity(); + var u = [1, 2, 3]; + var v = g_math.matrix4.transformPoint(a, g_math.matrix4.transformPoint(b, u)); + + var r = g_math.matrix4.compose(a, b); + + g_test.assertTrue(r == a); + sendTest(a, u, v); +}; + +g_suite.testCompose = function() { + var m = [[5, 2, -4, 1], [1, 0, 0, -2], [5, 6, 3, 2], [-1, -1, 2, 3]]; + var b = [[1, 2, 1, 1], [3, 4, 5, -1], [-1, -3, 4, 2], [1, 3, 2, 2]]; + var a = g_math.matrix4.composition(b, m); + var c = g_math.copyMatrix(b); + g_math.matrix4.compose(c, m); + + g_test.assertTrue(matrixDiff(a, c) < 0.001); +}; + +g_suite.testTranslation = function() { + var v = [1, 2, 3]; + var a = g_math.matrix4.identity(); + var r = g_math.matrix4.translate(a, v); + + g_test.assertTrue(r == a); + g_test.assertArrayEquals(a, g_math.matrix4.translation(v)); + g_test.assertArrayEquals(g_math.identity(3), g_math.matrix4.getUpper3x3(a)); + + sendTest(a, [0, 0, 0], v); +}; + +g_suite.testTranslate = function() { + var v = [1, 2, 3]; + var b = [[1, 2, 1, 1], [3, 4, 5, -1], [-1, -3, 4, 2], [1, 3, 2, 2]]; + var a = g_math.matrix4.translation(v); + var c = g_math.copyMatrix(b); + g_math.matrix4.translate(c, v); + + composeTest(a, b, c); +}; + +g_suite.testScaling = function() { + var v = [2, 3, 4]; + var a = g_math.matrix4.identity(); + var r = g_math.matrix4.scale(a, v); + + g_test.assertTrue(r == a); + g_test.assertTrue(matrixDiff(a, g_math.matrix4.scaling(v)) < 0.001); + + sendTest(a, [1, 0, 0], [v[0], 0, 0]); + sendTest(a, [0, 1, 0], [0, v[1], 0]); + sendTest(a, [0, 0, 1], [0, 0, v[2]]); +}; + +g_suite.testScale = function() { + var v = [2, 3, 4]; + var b = [[1, 2, 1, 1], [3, 4, 5, -1], [-1, -3, 4, 2], [1, 3, 2, 2]]; + var a = g_math.matrix4.scaling(v); + var c = g_math.copyMatrix(b); + g_math.matrix4.scale(c, v); + + composeTest(a, b, c); +}; + +g_suite.testRotationX = function() { + var a = g_math.matrix4.identity(); + var r = g_math.matrix4.rotateX(a, Math.PI / 2); + + g_test.assertTrue(r == a); + g_test.assertTrue( + matrixDiff(a, g_math.matrix4.rotationX(Math.PI / 2)) < 0.001); + + sendTest(a, [1, 0, 0], [1, 0, 0]); + sendTest(a, [0, 1, 0], [0, 0, 1]); + sendTest(a, [0, 0, 1], [0, -1, 0]); +}; + +g_suite.testRotateX = function() { + var angle = 1; + var b = [[1, 2, 1, 1], [3, 4, 5, -1], [-1, -3, 4, 2], [1, 3, 2, 2]]; + var a = g_math.matrix4.rotationX(angle); + var c = g_math.copyMatrix(b); + g_math.matrix4.rotateX(c, angle); + + composeTest(a, b, c); +}; + +g_suite.testRotationY = function() { + var a = g_math.matrix4.identity(); + var r = g_math.matrix4.rotateY(a, Math.PI / 2); + + g_test.assertTrue(r == a); + g_test.assertTrue( + matrixDiff(a, g_math.matrix4.rotationY(Math.PI / 2)) < 0.001); + + sendTest(a, [1, 0, 0], [0, 0, -1]); + sendTest(a, [0, 1, 0], [0, 1, 0]); + sendTest(a, [0, 0, 1], [1, 0, 0]); +}; + +g_suite.testRotateY = function() { + var angle = 1; + var b = [[1, 2, 1, 1], [3, 4, 5, -1], [-1, -3, 4, 2], [1, 3, 2, 2]]; + var a = g_math.matrix4.rotationY(angle); + var c = g_math.copyMatrix(b); + g_math.matrix4.rotateY(c, angle); + + composeTest(a, b, c); +}; + +g_suite.testRotationZ = function() { + var a = g_math.matrix4.identity(); + var r = g_math.matrix4.rotateZ(a, Math.PI / 2); + + g_test.assertTrue(r == a); + g_test.assertTrue( + matrixDiff(a, g_math.matrix4.rotationZ(Math.PI / 2)) < 0.001); + + sendTest(a, [1, 0, 0], [0, 1, 0]); + sendTest(a, [0, 1, 0], [-1, 0, 0]); + sendTest(a, [0, 0, 1], [0, 0, 1]); +}; + +g_suite.testRotateZ = function() { + var angle = 1; + var b = [[1, 2, 1, 1], [3, 4, 5, -1], [-1, -3, 4, 2], [1, 3, 2, 2]]; + var a = g_math.matrix4.rotationZ(angle); + var c = g_math.copyMatrix(b); + g_math.matrix4.rotateZ(c, angle); + + composeTest(a, b, c); +}; + +g_suite.testRotationZYX = function() { + var v = [1, 2, 3]; + var a = g_math.matrix4.identity(); + var r = g_math.matrix4.rotateZYX(a, v); + + g_test.assertTrue(r == a); + g_test.assertTrue(matrixDiff(a, g_math.matrix4.rotationZYX(v)) < 0.001); + + var b = g_math.matrix4.identity(); + g_math.matrix4.rotateZ(b, v[2]); + g_math.matrix4.rotateY(b, v[1]); + g_math.matrix4.rotateX(b, v[0]); + + g_test.assertTrue(matrixDiff(a, b) < 0.001); +}; + +g_suite.testRotateZYX = function() { + var v = [1, 2, 3]; + var b = [[1, 2, 1, 1], [3, 4, 5, -1], [-1, -3, 4, 2], [1, 3, 2, 2]]; + var a = g_math.matrix4.rotationZYX(v); + var c = g_math.copyMatrix(b); + g_math.matrix4.rotateZYX(c, v); + + composeTest(a, b, c); +}; + +g_suite.testAxisRotation = function() { + var angle = 1; + + g_test.assertTrue(matrixDiff(g_math.matrix4.axisRotation([1, 0, 0], angle), + g_math.matrix4.rotationX(angle)) < 0.001); + g_test.assertTrue(matrixDiff(g_math.matrix4.axisRotation([0, 1, 0], angle), + g_math.matrix4.rotationY(angle)) < 0.001); + g_test.assertTrue(matrixDiff(g_math.matrix4.axisRotation([0, 0, 1], angle), + g_math.matrix4.rotationZ(angle)) < 0.001); +}; + +g_suite.testAxisRotation111 = function() { + var v = [1, 1, 1]; + var a = g_math.matrix4.identity(); + var r = g_math.matrix4.axisRotate(a, v, 2 * Math.PI / 3); + + g_test.assertTrue(r == a); + g_test.assertTrue( + matrixDiff(a, g_math.matrix4.axisRotation(v, 2 * Math.PI / 3)) < 0.001); + + sendTest(a, [1, 0, 0], [0, 1, 0]); + sendTest(a, [0, 1, 0], [0, 0, 1]); + sendTest(a, [0, 0, 1], [1, 0, 0]); +}; + +g_suite.testAxisRotate = function() { + var v = [1, 2, 3]; + var angle = 1; + var b = [[1, 2, 1, 1], [3, 4, 5, -1], [-1, -3, 4, 2], [1, 3, 2, 2]]; + var a = g_math.matrix4.axisRotation(v, angle); + var c = g_math.copyMatrix(b); + g_math.matrix4.axisRotate(c, v, angle); + + composeTest(a, b, c); +}; + +// Tests that the 4-by-4 homogenous matrix M sends the 3-vector v to the +// 3-vector vM. +function sendTestVM(M, v, vM) { + g_test.assertTrue(matrixDiff([dehomogenize( + g_math.mulVectorMatrix(homogenize(v), M))], + [vM]) < 0.001); +} + +// Tests that the 4-by-4 homogenous matrix M sends the 3-vector v to the +// 3-vector Mv. +function sendTestMV(M, v, Mv) { + g_test.assertTrue(matrixDiff([dehomogenize( + g_math.mulMatrixVector(M, homogenize(v)))], [Mv]) < 0.001); +} + +// Tests that the 4-by-4 homogenous matrix M sends the 3-vector v to the +// 3-vector Mv when v is interpreted as a direction. +function directionSendTestVM(M, v, vM) { + g_test.assertTrue(matrixDiff([pop0( + g_math.mulVectorMatrix(push0(v), M))], [vM]) < 0.001); +} + +// Tests that the 4-by-4 homogenous matrix M sends the 3-vector v to the +// 3-vector Mv when v is interpreted as a direction. +function directionSendTestMV(M, v, Mv) { + g_test.assertTrue(matrixDiff([pop0( + g_math.mulMatrixVector(M, push0(v)))], [Mv]) < 0.001); +} + +// Tests whether if a is pre-composed with b, the result is c; assumes A * B +// precomposes a with b, as in row major. +function composeTestAB(a, b, c) { + g_test.assertTrue(matrixDiff(g_math.mulMatrixMatrix(a, b), c) < 0.001); +} + +// Tests whether if a is pre-composed with b, the result is c; assumes B * A +// precomposes a with b, as in column major. +function composeTestBA(a, b, c) { + g_test.assertTrue(matrixDiff(g_math.mulMatrixMatrix(b, a), c) < 0.001); +} + +window.onload = function() { + window.g_test = o3djs.test; + window.g_math = o3djs.math; + + // Whether or not a matrix transforms a vector by multiplying on + // the right or on the left depends on the choice of row major or column + // major. Tests which ask whether a matrix sends a point (or direction) to a + // particular other point (or direction) do so by appealing to the function + // sendTest (or directionSendTest). In row major mode, sendTest gets aliased + // to sendTestVM, in column major mode, sendTest gets aliased to sendTestMV, + // so in either mode, all the same tests should pass. + + window.sendTest = sendTestMV; + window.directionSendTest = directionSendTestMV; + window.composeTest = composeTestBA; + o3djs.math.installColumnMajorFunctions(); + var columnMajorTestResult = g_test.runTests(g_suite); + + window.sendTest = sendTestVM; + window.directionSendTest = directionSendTestVM; + window.composeTest = composeTestAB; + o3djs.math.installRowMajorFunctions(); + var rowMajorTestResult = g_test.runTests(g_suite); + + window.g_testResult = columnMajorTestResult && rowMajorTestResult; +}; + +</script> +</body> +</html> diff --git a/o3d/tests/selenium/tests/no-rendergraph.html b/o3d/tests/selenium/tests/no-rendergraph.html new file mode 100644 index 0000000..e35e648 --- /dev/null +++ b/o3d/tests/selenium/tests/no-rendergraph.html @@ -0,0 +1,80 @@ +<!-- +Copyright 2009, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + +<!-- +For checking what happens with no rendergraph. +--> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title> +No Rendergraph. +</title> +<!-- Include sample javascript library functions--> +<script type="text/javascript" src="../../../samples/o3djs/base.js"></script> + +<!-- Our javascript code --> +<script type="text/javascript"> +o3djs.require('o3djs.util'); + +// Events +// init() once the page has finished loading. +// unload() when the page is unloaded. +window.onload = init; + +/** + * Creates the client area. + */ +function init() { + o3djs.util.makeClients(initStep2); +} + +/** + * Initializes O3D and creates one shape. + * @param {Array} clientElements Array of o3d object elements. + */ +function initStep2(clientElements) { + window.g_client = clientElements[0].client; + window.g_testResult = true; +} +</script> +</head> +<body> +<h1>No Rendergraph</h1> +Area below should be a solid color. +<br/> +<!-- Start of O3D plugin --> +<div id="o3d" style="width: 800px; height: 600px"></div> +<!-- End of O3D plugin --> +</body> +</html> diff --git a/o3d/tests/selenium/tests/non-cachable-params.html b/o3d/tests/selenium/tests/non-cachable-params.html new file mode 100644 index 0000000..f506304 --- /dev/null +++ b/o3d/tests/selenium/tests/non-cachable-params.html @@ -0,0 +1,250 @@ +<!-- +Copyright 2009, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + +<!-- +Example of multiple views into the same scene. +--> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title> +Non Cachable Params +</title> +<!-- Include sample javascript library functions--> +<script type="text/javascript" src="../../../samples/o3djs/base.js"></script> + +<!-- Our javascript code --> +<script type="text/javascript"> +o3djs.require('o3djs.util'); +o3djs.require('o3djs.math'); +o3djs.require('o3djs.rendergraph'); +o3djs.require('o3djs.pack'); +o3djs.require('o3djs.camera'); +o3djs.require('o3djs.scene'); + +// Events +// init() once the page has finished loading. +// unload() when the page is unloaded. +window.onload = init; + +// global variables +var g_o3d; +var g_math; +var g_client; +var g_viewInfos = []; +var g_pack; +var g_o3d_width; // width of our client area +var g_o3d_height; // height of our client area + +/** + * Returns the path of where the file is located + * with the trailing slash + */ +function getCurrentPath() { + var path = window.location.href; + var index = path.lastIndexOf('/'); + return path.substring(0, index + 1); +} + +/** + * Loads a model into the transform graph and generates its corresponding entry + * in the render graph when it is done loading. + * @param {Pack} packfile_name filename of the collada model. + * @param {string} file_name filename of the collada model. + * @param {Transform} parent parent node in the transform graph to which to load + * the model into + */ +function loadModel(pack, file_name, parent) { + // Get our full path to the model + var model_path = getCurrentPath() + file_name; + + // Load the file given the full path, and call the callback function + // when its done loading. + o3djs.scene.loadScene(g_client, pack, parent, model_path, callback); + + /** + * Our callback is called once the model has been loaded into memory + * from the web or locally. + * @param {!o3d.Pack} pack The pack that was passed in above. + * @param {!o3d.Transform} parent The parent that was passed in above. + * @param {*} exception null if loading succeeded. + */ + function callback(pack, parent, exception) { + if (exception) { + alert('Could not load: ' + file_name + '\n' + exception); + } else { + // Get a cameraInfo (an object with a view and projection matrix) + // using our javascript library function + var cameraInfo = o3djs.camera.getViewAndProjectionFromCameras( + parent, + g_o3d_width / 2, // because this context only uses 1/2 the area + g_o3d_height); + + // Copy the view and projection to the draw context of the first view. + g_viewInfos[0].drawContext.view = cameraInfo.view; + g_viewInfos[0].drawContext.projection = cameraInfo.projection; + + // Generate draw elements and setup material draw lists. + o3djs.pack.preparePack(pack, g_viewInfos[0]); + + // for each effect, get a list of it's params and setup a param chain + // for the SAS params + var effects = pack.getObjectsByClassName('o3d.Effect'); + for (var ee = 0; ee < effects.length; ++ee) { + var effect = effects[ee]; + var paramInfos = effect.getParameterInfo(); + for (var pp = 0; pp < paramInfos.length; ++pp) { + var paramInfo = paramInfos[pp]; + if (paramInfo.sasClassName != "") { + var param = effect.createParam(paramInfo.name, 'ParamMatrix4'); + var sas_param = effect.createParam(paramInfo.name + "_sas", + paramInfo.sasClassName); + param.bind(sas_param); + } + } + } + window.g_testResult = true; + } + } +} + +/** + * Creates the client area. + */ +function init() { + o3djs.util.makeClients(initStep2); +} + +/** + * Initializes O3D and loads the model into the transform graph. + * @param {Array} clientElements Array of o3d object elements. + */ +function initStep2(clientElements) { + // Initializes global variables and libraries. + var o3d = clientElements[0]; + g_o3d = o3d.o3d; + g_math = o3djs.math; + g_client = o3d.client; + + // Initialize the sample javascript library. + o3djs.base.init(o3d); + + // Get the width and height of our client area. We will need this to create + // a projection matrix. + g_o3d_width = o3d.clientWidth; + g_o3d_height = o3d.clientHeight; + + // Creates a pack to manage our resources/assets + g_pack = g_client.createPack(); + + // Create the render graph for a view for the left half of screen. + g_viewInfos[0] = o3djs.rendergraph.createBasicView( + g_pack, + g_client.root, + g_client.renderGraphRoot, + [0.7, 0.2, 0.2, 1], + 0, + [0, 0, 0.5, 1]); // left half of screen. + + // Setup 3 areas. Each area needs a viewport, a tree traveral, 2 drawpasses + // and although we could clear the screen once let's do it per viewport just + // as an example. The original area is already setup except it needs a + // viewport setting. + + // make the 2 right viewports + for (var yy = 0; yy < 2; yy++) { + var viewInfo = o3djs.rendergraph.createExtraView( + g_viewInfos[0], + [0.5, yy * 0.5, 0.5, 0.5], // right half top or bottom. + [0.5, 0.2 + 0.5 * yy, 0.7 - 0.5 * yy, 1.0], // bg color. + yy + 1); // after the other views. + + // save if off for later? + g_viewInfos[g_viewInfos.length] = viewInfo; + + // Get the drawcontext for this area and set the view and + // projection matrices. + var drawContext = viewInfo.drawContext; + + if (yy == 0) { + drawContext.projection = g_math.matrix4.perspective( + 45 * 3.14159 / 180, + (g_o3d_width * 0.5) / (g_o3d_height * 0.5), + 0.1, + 100); + drawContext.view = g_math.matrix4.lookAt( + [-10, 3, -15], // eye + [0, 2, 0], // target + [0, 1, 0]); // up + } else { + // lets make this one orthographic + var aspect = g_o3d_width / g_o3d_height; + drawContext.projection = g_math.matrix4.orthographic( + -10, + 10, + -10 / aspect, + 10 / aspect, + 0, + 100); + // look directly from the front + drawContext.view = g_math.matrix4.lookAt( + [0, 5, 30], // eye + [0, 5, 0], // target + [0, 1, 0]); // up + } + } + + // Creates a transform to put our data on. + var my_data_root = g_pack.createObject('Transform'); + + // Connects our root to the client so that world matrices will + // get calculated. + my_data_root.parent = g_client.root; + + // Load the model into the transform graph as a child my_data_root + loadModel(g_pack, '../../../samples/assets/yard.o3dtgz', my_data_root); +} +</script> +</head> +<body> +<h1>Non Cachable Params</h1> +<br/> +Checks that non cachable param chains work by replacing all the standard (SAS) +params with chains to those params. If they are not working the 3 views will +show roughly the same image just with different aspect ratios. +<br/> +<!-- Start of O3D plugin --> +<div id="o3d" style="width: 800px; height: 600px;"></div> +<!-- End of O3D plugin --> +</body> +</html> diff --git a/o3d/tests/selenium/tests/offscreen-test.html b/o3d/tests/selenium/tests/offscreen-test.html new file mode 100644 index 0000000..033e0fa --- /dev/null +++ b/o3d/tests/selenium/tests/offscreen-test.html @@ -0,0 +1,158 @@ +<!-- +Copyright 2009, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + +<!-- +Offscreen Test + +Make sure client areas that are not visible are not rendered. +But that tick callbacks are called. +--> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title> +Offscreen Test. +</title> +<!-- Include sample javascript library functions--> +<script type="text/javascript" src="../../../samples/o3djs/base.js"></script> + +<!-- Our javascript code --> +<script type="text/javascript"> +o3djs.require('o3djs.util'); +o3djs.require('o3djs.rendergraph'); + +// Events +// init() once the page has finished loading. +// unload() when the page is unloaded. +window.onload = init; +window.onunload = uninit; + +// Events +// init() once the page has finished loading. +window.onload = init; + +// global variables +var g_clients = []; +var g_packs = []; +var g_viewInfos = []; +var g_renderCounts = [0, 0]; +var g_tickCounts = [0, 0]; +var g_testResult; + +function onRender(index) { + g_viewInfos[index].clearBuffer.clearColor = [Math.random(), + Math.random(), + Math.random(), + 1]; + g_renderCounts[index] += 1; + + // After 30 frames check that the offscreen client didn't render. + if (g_renderCounts[0] > 30) { + g_testResult = g_renderCounts[1] < 5 && + g_tickCounts[1] > 25 && + g_tickCounts[0] > 25; + } +} + +function onTick(index) { + g_tickCounts[index] += 1; +} + +/** + * Creates the client areas. + */ +function init() { + o3djs.util.makeClients(initStep2); +} + +/** + * Initializes O3D and loads the model into the transform graph. + * @param {Array} clientElements Array of o3d object elements. + */ +function initStep2(clientElements) { + for (var ii = 0; ii < clientElements.length; ++ii) { + var o3dElement = clientElements[ii]; + + g_clients[ii] = o3dElement.client; + g_packs[ii] = g_clients[ii].createPack(); + + g_viewInfos[ii] = o3djs.rendergraph.createBasicView( + g_packs[ii], + g_clients[ii].root, + g_clients[ii].renderGraphRoot); + + setRenderCallback(ii); + setTickCallback(ii); + } +} + +/** + * Sets the render callback such that it has access to the client. + * @param {!o3d.client} client The client to set the render callback on. + */ +function setRenderCallback(index) { + g_clients[index].setRenderCallback(function() { onRender(index); }); +} + +/** + * Sets the tick callback such that it has access to the client. + * @param {!o3d.client} client The client to set the tick callback on. + */ +function setTickCallback(index) { + g_clients[index].setTickCallback(function() { onTick(index); }); +} + +/** + * Cleans up. + */ +function uninit() { + for (var ii = 0; ii < g_clients.length; ++ii) { + g_clients[ii].clearRenderCallback(); + g_clients[ii].clearTickCallback(); + } +} + +</script> +</head> +<body> +<h1>Offscreen Test</h1> +This test verifies that client areas offscreen do not render but that tick +callbacs get called. +<br/> +<!-- Start of O3D plugin --> +<div id="o3d-on-screen" style="width: 100px; height: 100px;"></div> +<div style="width: 100px; height: 4000px; border: red 1px solid;"></div> +<div id="o3d-off-screen" style="width: 100px; height: 100px;"></div> +<!-- End of O3D plugin --> +</body> +</html> diff --git a/o3d/tests/selenium/tests/ownership-test.html b/o3d/tests/selenium/tests/ownership-test.html new file mode 100644 index 0000000..fea74f0 --- /dev/null +++ b/o3d/tests/selenium/tests/ownership-test.html @@ -0,0 +1,210 @@ +<!-- +Copyright 2009, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + +<!-- +A Selenium test to make that streams lasting past the client don't crash. +--> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title> +Ownership Test +</title> +<!-- Our javascript code --> +<script type="text/javascript" src="../../../samples/o3djs/base.js"></script> +<script type="text/javascript"> +o3djs.require('o3djs.util'); + +window.onload = init; + +// global variables +var g_testResult; +var g_streamArrays = []; +var g_effectInfo; + +/** + * Creates a o3d object. + */ +function init() { + // Create a client. + var clientSpan = document.getElementById('client'); + var objElem = o3djs.util.createClient(clientSpan); + objElem.style.width = '60px'; + objElem.style.height = '60px'; + objElem.id = 'o3d'; + objElem.name ='o3d'; + + // wait for the browsers to settle down. + var clearId = window.setInterval(function() { + if (document.o3d.o3d) { + window.clearInterval(clearId); + test(); + } + + }, 10); +} + +function makeBufferAndFreeClient() { + // Initialize global variables and libraries. + var o3d = document.o3d.o3d; + var client = document.o3d.client; + + // Create a g_pack to manage our resources/assets + var pack = client.createPack(); + + var effect = pack.createObject('Effect'); + effect.loadFromFXString('' + + 'float var1;\n' + + 'float2 var2;\n' + + 'float3 var3;\n' + + 'float4 var4;\n' + + 'struct a2v {\n' + + ' float4 pos : POSITION;\n' + + '};\n'+ + 'struct v2f {\n' + + ' float4 pos : POSITION;\n' + + '};\n' + + 'v2f vsMain(a2v IN) {\n' + + ' v2f OUT;\n' + + ' OUT.pos = IN.pos;\n' + + ' return OUT;\n' + + '}\n' + + 'float4 psMain(v2f IN): COLOR {\n' + + ' return float4(var1, var2.y, var3.z, var4.w);\n' + + '}\n' + + '// #o3d VertexShaderEntryPoint vsMain\n' + + '// #o3d PixelShaderEntryPoint psMain\n' + + '// #o3d MatrixLoadOrder RowMajor\n'); + g_effectInfo = effect.getParameterInfo(); + + + // Let's create a lot of buffers just to try to make it crash. + for (var ii = 0; ii < 100; ii++) { + var bank = pack.createObject('StreamBank'); + var buffer = pack.createObject('VertexBuffer'); + var field = buffer.createField('FloatField', 3); + + var vertsArray = [ + // Triangle 1 + -0.5, 0.5, 0, + -0.5, -0.5, 0, + 0.5, -0.5, 0, + + // Triangle 2 + 0.5, 0.5, 0, + -0.5, 0.5, 0, + 0.5, -0.5, 0 + ]; + buffer.set(vertsArray); + bank.setVertexStream(o3d.Stream.POSITION, + 0, + field, + 0); + + // copy the streams out so they last past the client. + g_streamArrays[ii] = bank.vertexStreams; + } + + pack.destroy(); + + var clientSpan = document.getElementById('client'); + var clientNode = clientSpan.childNodes[0]; + clientSpan.removeChild(clientNode); +} + +function isDefined(variable) { + return (typeof(variable) == "undefined") ? false : true; +} + +function test() { + makeBufferAndFreeClient(); + + // check that we can still access the stream objects. + var caught = false; + try { + // Chrome does not always throw exceptions when methods/properties on NPAPI + // objects fail, so we explicitly throw here. + var stream = g_streamArrays[1][0]; + if (!isDefined(stream)) + throw 'error'; + + // The stream object may exist as an empty container, so probe its normally + // expected properties - they should no longer exist. + var semantic = stream.semantic; + var field = stream.field; + + // The object was deleted, so both of its properties should not exist. + if (!isDefined(semantic) && !isDefined(field)) + throw 'error' + } catch (e) { + // We should always get here unless there is a bug. + caught = true; + } + + var caught2 = false; + try { + var effectInfo = g_effectInfo[0]; + var name = effect.name; + if (!isDefined(name)) { + throw 'error'; + } + } catch(e) { + // We should always get here unless there is a bug. + caught2 = true; + } + + // This should free the Stream objects. + g_streamArrays = null; + + // attempt to allocate lots of stuff to hopefully force the browser + // to garbage collect. If there is a bug we should crash here. + var array = {}; + for (var ii = 0; ii < 100000; ii++) { + array['abced' + ii] = 'this is a waste of memory'; + } + + if (caught && caught2) + document.getElementById('testStatus').innerHTML = "Finished - Passed"; + else + document.getElementById('testStatus').innerHTML = "Finished - Failed"; + g_testResult = caught; +} + +</script> +</head> +<body> +<h1>Ownership Test</h1> +<div id="client" style="width: 60px; height 60px;"></div> +<div>Status: <span id="testStatus">--running--</span></div> +</body> +</html> diff --git a/o3d/tests/selenium/tests/pixel-perfection.html b/o3d/tests/selenium/tests/pixel-perfection.html new file mode 100644 index 0000000..60e7b1c --- /dev/null +++ b/o3d/tests/selenium/tests/pixel-perfection.html @@ -0,0 +1,337 @@ +<!-- +Copyright 2009, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + +<!-- +O3D Pixel Perfection Test + +This test generates some shapes that should be able to be rendered +identically on all the platforms that we support. It tests fill +coverage, zbuffer coverage, blending and color and brightness fidelity. + +It purposly does not test things like anti-aliasing and texture +sampling, because those vary too much from vendor to vendor, and +because they are tested adequately in other tests. + +TODO: Anti-aliasing should be turned off for this test, when +we have a way to do that. +--> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title> +Pixel Perfection +</title> +<script type="text/javascript" src="../../../samples/o3djs/base.js"></script> +<script type="text/javascript"> +o3djs.require('o3djs.effect'); +o3djs.require('o3djs.material'); +o3djs.require('o3djs.math'); +o3djs.require('o3djs.primitives'); +o3djs.require('o3djs.rendergraph'); +o3djs.require('o3djs.util'); + +// global variables +var g_o3dElement; +var g_client; +var g_o3d; +var g_math; +var g_pack; +var g_viewInfo; + +var g_vertexShaderMaterial; +var g_lightPosition = [0, 0, 12]; +var g_eyePosition = [0, 0, 12]; + +/** + * Creates the client area. + */ +function initClient() { + window.g_finished = false; // for selenium testing. + + // Runs the sample in V8. Comment out this line to run it in the browser + // JavaScript engine, for example if you want to debug it. + o3djs.util.setMainEngine(o3djs.util.Engine.V8); + + o3djs.util.makeClients(main, 'NotAntiAliased'); +} + +/** + * Initializes global variables, positions camera, draws shapes. + * @param {Array} clientElements Array of o3d object elements. + */ +function main(clientElements) { + // Init global variables. + initGlobals(clientElements); + + // Set up the view and projection transformations. + initContext(); + + // Add the shapes to the transform heirarchy. + createShapes(); + + window.g_testResult = true; // for selenium testing. +} + +/** + * Initializes global variables and libraries. + */ +function initGlobals(clientElements) { + g_o3dElement = clientElements[0]; + window.g_client = g_client = g_o3dElement.client; + g_o3d = g_o3dElement.o3d; + g_math = o3djs.math; + + // Create a pack to manage the objects created. + g_pack = g_client.createPack(); + + // Create the render graph for a view. + g_viewInfo = o3djs.rendergraph.createBasicView( + g_pack, + g_client.root, + g_client.renderGraphRoot); + + // Set the background color to white for more contrast. + g_viewInfo.clearBuffer.clearColor = [1, 1, 1, 1]; + + // Create and load the effect. + var effect = g_pack.createObject('Effect'); + var vertexShaderString = o3djs.util.getElementContentById('vertexShader'); + effect.loadFromFXString(vertexShaderString); + // Create a material for it. + g_vertexShaderMaterial = g_pack.createObject('Material'); + + // Set the material's drawList + g_vertexShaderMaterial.drawList = g_viewInfo.performanceDrawList; + + // Apply our effect to this material. The effect tells the 3D hardware + // which shader to use. + g_vertexShaderMaterial.effect = effect; + + // Create the parameters the effect needs on the material. + effect.createUniformParameters(g_vertexShaderMaterial); +} + +/** + * Sets up reasonable view and projection matrices. + */ +function initContext() { + // Set up a perspective transformation for the projection. + g_viewInfo.drawContext.projection = g_math.matrix4.perspective( + g_math.degToRad(30), // 30 degree frustum. + g_o3dElement.clientWidth / g_o3dElement.clientHeight, // Aspect ratio. + 1, // Near plane. + 5000); // Far plane. + + // Set up our view transformation to look towards the world origin where the + // primitives are located. + g_viewInfo.drawContext.view = g_math.matrix4.lookAt( + g_eyePosition, // eye + [0, 0, 0], // target + [0, 1, 0]); // up +} + +/** + * Creates a phong material based on the given single color. + * @param {Array} baseColor An array with 4 entries, the R,G,B, and A components + * of a color. + * @return {Material} A phong material whose overall pigment is baseColor. + */ +function createMaterial(baseColor) { + // Create a material. + var material = o3djs.material.createBasicMaterial( + g_pack, + g_viewInfo, + baseColor, + baseColor[3] != 1.0); + + return material; +} + +/** + * Creates shapes using the primitives utility library, and adds them to the + * transform graph at the root node. + */ +function createShapes() { + var cube = o3djs.primitives.createRainbowCube( + g_pack, + g_vertexShaderMaterial, + Math.sqrt(2)); + + var sphere = o3djs.primitives.createSphere( + g_pack, + createMaterial([1, 0, 0, 1]), + 1.0, // Radius of the sphere. + 30, // Number of meridians. + 20); // Number of parallels. + + var plane1 = o3djs.primitives.createPlane( + g_pack, + createMaterial([0, 1, 1, 1]), + 2.5, // Width. + 2.5, // Depth. + 3, // Horizontal subdivisions. + 3); // Vertical subdivisions. + + var plane2 = o3djs.primitives.createPlane( + g_pack, + createMaterial([0, .5, 0, 1]), + 2.5, // Width. + 2.5, // Depth. + 3, // Horizontal subdivisions. + 3); // Vertical subdivisions. + + var transPlane1 = o3djs.primitives.createPlane( + g_pack, + createMaterial([0, 1, 1, .1]), + 2.5, // Width. + 2.5, // Depth. + 3, // Horizontal subdivisions. + 3); // Vertical subdivisions. + + var transPlane2 = o3djs.primitives.createPlane( + g_pack, + createMaterial([0, .5, 0, .1]), + 2.5, // Width. + 2.5, // Depth. + 3, // Horizontal subdivisions. + 3); // Vertical subdivisions. + + var disc1 = o3djs.primitives.createDisc( + g_pack, + createMaterial([0, 0, 0, 0.25]), + 1, // Radius. + 50, // Divisions. + 2, // Stacks. + 1, // Start Stack. + 1); // Stack Power. + + var disc2 = o3djs.primitives.createDisc( + g_pack, + createMaterial([0, 0, 0, 1]), + 1, // Radius. + 50, // Divisions. + 2, // Stacks. + 1, // Start Stack. + 1); // Stack Power. + + // Add the shapes to the transforms. + var transformTable = [ + {shape: cube, translation: [-2, 1, 0], + rotation: [Math.PI / 4, Math.PI / 4, 0]}, + {shape: sphere, translation: [0, 1, 0], rotation: [0, 0, 0]}, + {shape: plane1, translation: [2, 1, 0], + rotation: [0.99 * Math.PI / 2, 0, 0]}, + {shape: plane2, translation: [2, 1, 0], rotation: [Math.PI / 2, 0, 0]}, + {shape: transPlane1, translation: [-2, -1, -0.1], + rotation: [0.99 * Math.PI / 2, 0, 0]}, + {shape: transPlane2, translation: [-2, -1, -0.1], + rotation: [Math.PI / 2, 0, 0]}, + {shape: disc1, translation: [0, -1, 0], rotation: [Math.PI / 2, 0, 0]}, + {shape: disc2, translation: [2, -1, 0], rotation: [Math.PI / 2, 0, 0]} + ]; + + for (var tt = 0; tt < transformTable.length; ++tt) { + var transform = g_pack.createObject('Transform'); + transform.addShape(transformTable[tt].shape); + transform.translate(transformTable[tt].translation); + transform.rotateX(transformTable[tt].rotation[0]); + transform.rotateY(transformTable[tt].rotation[1]); + transform.rotateZ(transformTable[tt].rotation[2]); + transform.parent = g_client.root; + } +} + + +</script> +</head> +<body onload="initClient()"> +<h1>Pixel Perfection</h1> +<p>This test generates some shapes that should be able to be rendered +identically on all the platforms that we support. It tests things +like fill coverage, zbuffer coverage, blending and color/brightness +fidelity.</p> +<br/> +<!-- Start of O3D plugin --> +<div id="o3d" style="width: 600px; height: 600px;"></div> +<!-- End of O3D plugin --> +<!-- Start of effect --> +<textarea id="vertexShader" name="vertexShader" cols="80" rows="20" + style="display: none;"> +// The 4x4 world view projection matrix. +float4x4 worldViewProjection : WORLDVIEWPROJECTION; + +// input parameters for our vertex shader +struct PixelShaderInput { + float4 position : POSITION; + float4 color : COLOR; +}; + +// input parameters for our pixel shader +// also the output parameters for our vertex shader +struct VertexShaderInput { + float4 position : POSITION; + float4 color: COLOR; +}; + +/** + * Vertex Shader - our vertex shader + */ +PixelShaderInput vertexShaderFunction(VertexShaderInput input) { + /** + * Our vertex shader projects the vertices onto the screen. + * We return its color unchanged. + */ + PixelShaderInput output; + + output.position = mul(input.position, worldViewProjection); + output.color = input.color; + return output; +} + +/** + * pixel shader does nothing but return whatever color it was given. + */ +float4 pixelShaderFunction(PixelShaderInput input): COLOR { + return input.color; +} + +// Here we tell our effect file the functions +// which specify our vertex and pixel shaders. + +// #o3d VertexShaderEntryPoint vertexShaderFunction +// #o3d PixelShaderEntryPoint pixelShaderFunction +// #o3d MatrixLoadOrder RowMajor +</textarea> +<!-- End of effect --> +</body> +</html> diff --git a/o3d/tests/selenium/tests/quaternion-test.html b/o3d/tests/selenium/tests/quaternion-test.html new file mode 100644 index 0000000..1d37182 --- /dev/null +++ b/o3d/tests/selenium/tests/quaternion-test.html @@ -0,0 +1,335 @@ +<!-- +Copyright 2009, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title> +Quaternion Test +</title> +</head> +<body> +<h1>Quaternion Test</h1> +This tests the quaternion utility library. +<br/> +<script type="text/javascript" + src="../../../samples/o3djs/base.js"></script> +<script type="text/javascript"> + +o3djs.require('o3djs.math'); +o3djs.require('o3djs.quaternions'); +o3djs.require('o3djs.test'); + +var g_suite = {}; + +g_suite.testType = function() { + g_test.assertEquals(g_quat.mathType(1), "Scalar"); + g_test.assertEquals(g_quat.mathType([1, 2, 3, 4]), "Quaternion"); +}; + +g_suite.testNegative = function() { + g_test.assertArrayEquals([0, 6, 7, -1], g_quat.negative([0, -6, -7, 1])); +}; + +g_suite.testCopy = function() { + var a = [0, 6, 7, 1]; + var b = g_quat.copy(a); + g_test.assertArrayEquals(a, b); + g_test.assertFalse(a == b); +}; + +g_suite.testAddQuaternions = function() { + g_test.assertArrayEquals([0, 6, 7, 1], + g_quat.add([1, 2, 3, 2], [-1, 4, 4, -1])); + g_test.assertArrayEquals([1, -1, -1, 2], + g_quat.add([0, 0, 0, 0], [1, -1, -1, 2])); +}; + +g_suite.testAddQuaternionsAndScalars = function() { + g_test.assertArrayEquals([0, 6, 7, 2], g_quat.add([0, 6, 7, 1], 1)); + g_test.assertArrayEquals([0, 6, 7, 2], g_quat.add(1, [0, 6, 7, 1])); +}; + +g_suite.testSubQuaternions = function() { + g_test.assertArrayEquals([2, -2, -1, 4], + g_quat.sub([1, 2, 3, 4], [-1, 4, 4, 0])); +}; + +g_suite.testSubQuaternionsAndScalars = function() { + g_test.assertArrayEquals([0, 6, 7, 0], g_quat.sub([0, 6, 7, 1], 1)); + g_test.assertArrayEquals([0, -6, -7, 0], g_quat.sub(1, [0, 6, 7, 1])); +}; + +g_suite.testMulQuaternions = function() { + // 2*3 = 6 + g_test.assertArrayEquals([0, 0, 0, 6], + g_quat.mul([0, 0, 0, 2], [0, 0, 0, 3])); + + // i^2 = -1 + g_test.assertArrayEquals([0, 0, 0, -1], + g_quat.mul([1, 0, 0, 0], [1, 0, 0, 0])); + + // j^2 = -1 + g_test.assertArrayEquals([0, 0, 0, -1], + g_quat.mul([0, 1, 0, 0], [0, 1, 0, 0])); + + // k^2 = -1 + g_test.assertArrayEquals([0, 0, 0, -1], + g_quat.mul([0, 0, 1, 0], [0, 0, 1, 0])); + + // i*j = k + g_test.assertArrayEquals([0, 0, 1, 0], + g_quat.mul([1, 0, 0, 0], [0, 1, 0, 0])); +}; + +g_suite.testMulQuaternionsAndScalars = function() { + g_test.assertArrayEquals([2, 4, 6, 8], g_quat.mul([1, 2, 3, 4], 2)); + g_test.assertArrayEquals([2, 4, 6, 8], g_quat.mul(2, [1, 2, 3, 4])); +}; + +g_suite.testDivQuaternions = function() { + var q = [-1, 5, -4, 2]; + var r = [4, 4, 2, -2]; + assertQuaternionsClose(r, g_quat.mul(g_quat.div(r, q), q)); +}; + +g_suite.testDivQuaternionScalar = function() { + g_test.assertArrayEquals([0.5, 1, 1.5, 2], g_quat.div([1, 2, 3, 4], 2)); +}; + +g_suite.testDivScalarQuaternion = function() { + var q = [4, 2, -1, 7]; + var k = 3; + assertQuaternionsClose([0, 0, 0, k], g_quat.mul(q, g_quat.div(k, q))); + assertQuaternionsClose([0, 0, 0, k], g_quat.mul(g_quat.div(k, q), q)); +}; + +g_suite.testDivDirection = function() { + var q = [4, 2, -1, 7]; + var r = [4, 4, 2, -2]; + assertQuaternionsClose(g_quat.div(q, r), g_quat.mul(q, g_quat.div(1, r))); +}; + +g_suite.testLength = function() { + g_test.assertEquals(13, g_quat.length([5, 12, 0, 0])); + g_test.assertEquals(13, g_quat.length([0, 0, 5, 12])); + g_test.assertClose(Math.sqrt(30), g_quat.length([1, 2, 3, 4])); +}; + +g_suite.testLengthSquared = function() { + g_test.assertEquals(30, g_quat.lengthSquared([1, 2, 3, 4])); +}; + +g_suite.testNormalize = function() { + g_test.assertTrue(compareWithTolerance(1, + g_quat.length(g_quat.normalize([1, 2, 3, 4])), 1e-4)); +}; + +g_suite.testConjugate = function() { + g_test.assertArrayEquals([-1, -2, -3, 4], g_quat.conjugate([1, 2, 3, 4])); +}; + +g_suite.testRotationX = function() { + var q = g_quat.rotationX(Math.PI / 2); + var v = [0, 1, 0, 0]; // Y rotated around the X axis should be Z. + assertVectorsClose(g_quat.mul(q, g_quat.div(v, q)), [0, 0, 1, 0]); +}; + +g_suite.testRotationY = function() { + var q = g_quat.rotationY(Math.PI / 2); + var v = [0, 0, 1, 0]; // Z rotated around the Y axis should be X. + assertVectorsClose(g_quat.mul(q, g_quat.div(v, q)), [1, 0, 0, 0]); +}; + +g_suite.testRotationZ = function() { + var q = g_quat.rotationZ(Math.PI / 2); + var v = [1, 0, 0, 0]; // X rotated around the Z axis should be Y. + assertVectorsClose(g_quat.mul(q, g_quat.div(v, q)), [0, 1, 0, 0]); +}; + +g_suite.testRotationVarious = function() { + var v = g_quat.rotationX(0); + assertMatricesClose(g_math.matrix4.rotationX(1), + g_quat.quaternionToRotation(g_quat.rotationX(1))); + assertMatricesClose(g_math.matrix4.rotationY(1), + g_quat.quaternionToRotation(g_quat.rotationY(1))); + assertMatricesClose(g_math.matrix4.rotationZ(1), + g_quat.quaternionToRotation(g_quat.rotationZ(1))); + assertMatricesClose(g_math.matrix4.identity(), + g_quat.quaternionToRotation([0, 0, 0, 1])); + + var axis = [1, -4, 2]; + var angle = 3; + assertMatricesClose( + g_math.matrix4.axisRotation(axis, angle), + g_quat.quaternionToRotation(g_quat.axisRotation(axis, angle))); +}; + +g_suite.testAxisRotation = function() { + var q = g_quat.axisRotation([1, 1, 1], 2 * Math.PI / 3); + assertVectorsClose(g_quat.mul(q, g_quat.div([1, 0, 0, 0], q)), [0, 1, 0, 0]); + assertVectorsClose(g_quat.mul(q, g_quat.div([0, 1, 0, 0], q)), [0, 0, 1, 0]); + assertVectorsClose(g_quat.mul(q, g_quat.div([0, 0, 1, 0], q)), [1, 0, 0, 0]); +}; + +g_suite.testQuaternionToRotation = function() { + // The quaternion 1, should give the identity transformation. + assertMatricesClose(g_math.matrix4.identity(), + g_quat.quaternionToRotation([0, 0, 0, 1])); + + // Each of i, j, and k should rotate 180 degrees around the x, y and z axes + // (respectively). + assertMatricesClose(g_math.matrix4.rotationX(Math.PI), + g_quat.quaternionToRotation([1, 0, 0, 0])); + assertMatricesClose(g_math.matrix4.rotationY(Math.PI), + g_quat.quaternionToRotation([0, 1, 0, 0])); + assertMatricesClose(g_math.matrix4.rotationZ(Math.PI), + g_quat.quaternionToRotation([0, 0, 1, 0])); + + // Pick an arbitrary point v and quaternion q. + var v = [1, 2, 3, 1]; + var q = [2, -7, 4, -3]; + + // Convert the vector to a quatnerion, apply q, and convert back. + var t1 = toPoint(g_quat.div(g_quat.mul(q, toQuat(v)), q)); + // Also apply the matrix obtained from quaternionToRotation. + var t2 = g_math.mulVectorMatrix(v, g_quat.quaternionToRotation(q)); + + // Results should be the same. + assertVectorsClose(t1, t2); +}; + +g_suite.testRotationToQuaternion = function() { + // Start with a bunch of haphazard rotation matrices. + var matrices = [g_math.matrix4.axisRotation([1, -2, 0], 1), + g_math.matrix4.axisRotation([2, -4, -1], -.1), + g_math.matrix4.axisRotation([-1, -4, -1], 1), + g_math.matrix4.axisRotation([-1, -3, 2], .1), + g_math.matrix4.axisRotation([2, -7, -1], -5), + g_math.matrix4.axisRotation([1, -7, 6], .5), + g_math.matrix4.axisRotation([-2, 7, -6], 3), + g_math.matrix4.axisRotation([-2, -2, -6], -3), + g_math.matrix4.axisRotation([-4, -2, 3], .4), + g_math.matrix4.axisRotation([-1, -2, -3], -1) + ]; + + // Test each one. + for (var i = 0; i < matrices.length; ++i){ + toQuaternionAndBack(matrices[i]); + } +}; + +function toQuaternionAndBack(m1) +{ + // Convert the matrix to a quaternion. + var q = g_quat.rotationToQuaternion(m1); + + // Then convert back. + var m2 = g_quat.quaternionToRotation(q); + + // Assert that you get the same matrix you started with. + assertMatricesClose(m1, m2); +}; + +g_suite.testInverse = function() { + var q = [1, 2, 3, 4]; + + // The inverse quaternion should give you the inverse matrix. + var m1 = g_quat.quaternionToRotation(g_quat.inverse(q)); + var m2 = g_math.inverse(g_quat.quaternionToRotation(q)); + + assertMatricesClose(m1, m2); +}; + +// Asks if two numbers are within a tolerance of eachother. +function compareWithTolerance(a, b, tol) { + return Math.abs(a-b) < tol; +}; + +// Compares two quaternions by subtracting them, taking the length of the +// difference, and comparing that length to a tolerance. +function compareQuaternionsWithTolerance(a, b, tol) { + return g_quat.length(g_quat.sub(a,b)) < tol; +}; + +function assertQuaternionsClose(a, b) { + g_test.assertTrue(compareQuaternionsWithTolerance(a, b, 1e-4)); +}; + +// Compares two vectors by subtracting them, taking the length of the +// difference and comparing that length to a tolerance. +function compareVectorsWithTolerance(a, b, tol) { + return g_math.length(g_math.subVector(a,b)) < tol; +}; + +function assertVectorsClose(a, b) { + g_test.assertTrue(compareVectorsWithTolerance(a, b, 1e-4)); +}; + +// The square root of the sum of squares of the entries of a matrix. +function frobeniusNorm(a) { + return Math.sqrt(g_math.trace( + g_math.mulMatrixMatrix(g_math.transpose(a), a))); +}; + +// The sum of squares of entries of the difference between two matrices. +function matrixDiff(a, b) { + return frobeniusNorm(g_math.subMatrix(a, b)); +}; + +function assertMatricesClose(a, b) { + g_test.assertTrue(matrixDiff(a, b) < 1e-4); +}; + +// Creates a quaternion from a vector; assumes that either the vector has three +// entries or it is in homogenous coordinates with a w component of 1. +function toQuat(v) { + return [v[0], v[1], v[2], 0]; +}; + +// Reinterprets a quaternion as a point in homogenous coordinates with a w +// component of 1. +function toPoint(q) { + return [q[0], q[1], q[2], 1]; +}; + +window.onload = function() { + window.g_quat = o3djs.quaternions; + window.g_math = o3djs.math; + window.g_test = o3djs.test; + window.g_testResult = g_test.runTests(g_suite); +}; + +</script> +</body> +</html> diff --git a/o3d/tests/selenium/tests/render-test.html b/o3d/tests/selenium/tests/render-test.html new file mode 100644 index 0000000..3b4e26a --- /dev/null +++ b/o3d/tests/selenium/tests/render-test.html @@ -0,0 +1,136 @@ +<!-- +Copyright 2009, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + +<!-- +Render Test + +Make sure that if client.render() is called multiple times it is only rendered +once. client.render() should only flag that the client needs to be rendered and +the system (browser + plugin) should render it the next time it's time to +render. It should NOT render immediately therefore multiple calls to +client.render() without returning to the browser should only make it render +once. +--> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title> +Render Test. +</title> +<!-- Include sample javascript library functions--> +<script type="text/javascript" src="../../../samples/o3djs/base.js"></script> + +<!-- Our javascript code --> +<script type="text/javascript"> +o3djs.require('o3djs.util'); +o3djs.require('o3djs.rendergraph'); + +// Events +// init() once the page has finished loading. +// unload() when the page is unloaded. +window.onload = init; +window.onunload = uninit; + +// Events +// init() once the page has finished loading. +window.onload = init; + +// global variables +var g_client; +var g_renderCount = 0; + +function onRender() { + ++g_renderCount; +} + +/** + * Creates the client areas. + */ +function init() { + o3djs.util.makeClients(initStep2); +} + +/** + * Initializes O3D. + * @param {Array} clientElements Array of o3d object elements. + */ +function initStep2(clientElements) { + var o3dElement = clientElements[0]; + + var o3d = o3dElement.o3d; + g_client = o3dElement.client; + g_client.renderMode = o3d.Client.RENDERMODE_ON_DEMAND; + + g_client.setRenderCallback(onRender); + + for (var ii = 0; ii < 60; ++ii) { + g_client.render(); + } + + setTimeout(checkResults, 1000); +} + +function checkResults() { + // We give it some leeway in case the browser is settling down. + window.g_testResult = g_renderCount < 5; + + document.getElementById('success').innerHTML = + g_testResult ? 'pass' : '<font color="red">fail</font>'; +} + +/** + * Cleans up. + */ +function uninit() { + if (g_client) { + g_client.cleanup(); + } +} + +</script> +</head> +<body> +<h1>Render Test</h1> +Make sure that if client.render() is called multiple times it is only rendered +once. client.render() should only flag that the client needs to be rendered and +the system (browser + plugin) should render it the next time it's time to +render. It should NOT render immediately therefore multiple calls to +client.render() without returning to the browser should only make it render +once. +<br/> +<!-- Start of O3D plugin --> +<div id="o3d" style="width: 100px; height: 100px;"></div> +<!-- End of O3D plugin --> +<div>Test Results: <span id="success"></span></div> +</body> +</html> diff --git a/o3d/tests/selenium/tests/serialization-test.html b/o3d/tests/selenium/tests/serialization-test.html new file mode 100644 index 0000000..dcb5ddc --- /dev/null +++ b/o3d/tests/selenium/tests/serialization-test.html @@ -0,0 +1,1376 @@ +<!-- +Copyright 2009, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title> +Deserialization Test +</title> +</head> +<body> +<h1>Deserialization Test</h1> +This tests deserialization of packs from JSON. +<br/> +<!-- Start of O3D plugin --> +<div id="o3d" style="width: 32px; height: 32px;"></div> +<!-- End of O3D plugin --> + +<script type="text/javascript" + src="../../../samples/o3djs/base.js"></script> +<script type="text/javascript"> + +o3djs.require('o3djs.io'); +o3djs.require('o3djs.serialization'); +o3djs.require('o3djs.test'); +o3djs.require('o3djs.util'); + +var g_suite = {}; + +g_suite.testDeserializesEmptyPack = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + } + }; + + var pack = g_client.createPack(); + o3djs.serialization.deserialize(pack, json); + g_test.assertEquals(0, pack.objects.length); +}; + +g_suite.testExceptionIfVersionIsMissing = function() { + var json = { + objects: { + } + }; + + var pack = g_client.createPack(); + var exception = null; + try { + o3djs.serialization.deserialize(pack, json); + } catch(e) { + exception = e; + } + + g_test.assertEquals('Version in JSON file was missing.', exception); + g_test.assertEquals(0, pack.objects.length); +}; + +g_suite.testExceptionIfVersionIsUnsupported = function() { + var json = { + version: 0, + objects: { + } + }; + + var pack = g_client.createPack(); + var exception = null; + try { + o3djs.serialization.deserialize(pack, json); + } catch(e) { + exception = e; + } + + g_test.assertEquals( + 'Version in JSON file was 0 but expected at least version ' + + o3djs.serialization.supportedVersion + '.', exception); + g_test.assertEquals(0, pack.objects.length); +}; + +g_suite.testExceptionIfObjectsArrayIsMissing = function() { + var json = { + version: o3djs.serialization.supportedVersion + }; + + var pack = g_client.createPack(); + var exception = null; + try { + o3djs.serialization.deserialize(pack, json); + } catch(e) { + exception = e; + } + + g_test.assertEquals('Objects array in JSON file was missing.', exception); + g_test.assertEquals(0, pack.objects.length); +}; + +g_suite.testDeserializesObject = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.Transform': [ + { + } + ] + } + }; + + var pack = g_client.createPack(); + o3djs.serialization.deserialize(pack, json); + + g_test.assertEquals(1, pack.objects.length); + g_test.assertEquals('o3d.Transform', pack.objects[0].className); +}; + +g_suite.testDeserializesIntoExistingObjectIfItIsAlreadyAdded = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.Transform': [ + { + id: 7, + properties: { + name: 'Foo' + } + } + ] + } + }; + + var pack = g_client.createPack(); + var transform = pack.createObject('o3d.Transform'); + var deserializer = o3djs.serialization.createDeserializer(pack, json); + deserializer.addObject(7, transform); + deserializer.run(); + + g_test.assertEquals(1, pack.objects.length); + g_test.assertEquals('o3d.Transform', pack.objects[0].className); + g_test.assertEquals(transform.clientId, pack.objects[0].clientId); + g_test.assertEquals('Foo', pack.objects[0].name); +}; + +g_suite.testCreatesSpecialClassByInvokingCallback = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.Transform': [ + { + id: 7 + } + ], + 'myname.SpecialClass': [ + { + parent: 7 + } + ] + } + }; + + var pack = g_client.createPack(); + var deserializer = o3djs.serialization.createDeserializer(pack, json); + + deserializer.createCallbacks['myname.SpecialClass'] = function( + deserializer, json) { + var transform = deserializer.pack.createObject('o3d.Transform'); + transform.parent = deserializer.getObjectById(json.parent); + return transform; + }; + + deserializer.run(); + + g_test.assertEquals(2, pack.objects.length); + g_test.assertEquals(pack.objects[0].children[0].clientId, + pack.objects[1].clientId); +}; + +g_suite.testDeserializesBoolProperty = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.Transform': [ + { + properties: { + cull: true + } + } + ] + } + }; + + var pack = g_client.createPack(); + o3djs.serialization.deserialize(pack, json); + + g_test.assertEquals(1, pack.objects.length); + g_test.assertEquals(true, pack.objects[0].cull); +}; + +g_suite.testDeserializesMatrixProperty = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.Transform': [ + { + properties: { + localMatrix: [[1,2,3,4],[5,6,7,8],[8,7,6,5],[4,3,2,1]] + } + } + ] + } + }; + + var pack = g_client.createPack(); + o3djs.serialization.deserialize(pack, json); + + g_test.assertEquals(1, pack.objects.length); + g_test.assertEquals(4, pack.objects[0].localMatrix[3][0]); +}; + +g_suite.testDeserializesStringProperty = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.Transform': [ + { + properties: { + name: 'myTransform' + } + } + ] + } + }; + + var pack = g_client.createPack(); + o3djs.serialization.deserialize(pack, json); + + g_test.assertEquals(1, pack.objects.length); + g_test.assertEquals('myTransform', pack.objects[0].name); +}; + +g_suite.testShouldDeserializeNullKeywordToNullValue = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.FunctionEval': [ + { + properties: { + 'functionObject': null + } + } + ] + } + }; + + var pack = g_client.createPack(); + o3djs.serialization.deserialize(pack, json); + + g_test.assertEquals(1, pack.objects.length); + g_test.assertNull(pack.objects[0].functionObject); +}; + +g_suite.testDeserializesReferenceProperty = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.Curve': [ + { + id: 7 + } + ], + 'o3d.FunctionEval': [ + { + properties: { + 'functionObject': { ref: 7 } + } + } + ] + } + }; + + var pack = g_client.createPack(); + o3djs.serialization.deserialize(pack, json); + + g_test.assertEquals(2, pack.objects.length); + g_test.assertEquals(pack.objects[0].clientId, pack.objects[1].functionObject.clientId); +}; + +g_suite.testDeserializesAndFixesUpReferenceProperty = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.FunctionEval': [ + { + properties: { + 'functionObject': { ref: 7 } + } + } + ], + 'o3d.Curve': [ + { + id: 7 + } + ] + } + }; + + var pack = g_client.createPack(); + o3djs.serialization.deserialize(pack, json); + + g_test.assertEquals(2, pack.objects.length); + g_test.assertEquals(pack.objects[1].clientId, pack.objects[0].functionObject.clientId); +}; + +g_suite.testExceptionIfReferenceCannotBeResolved = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.FunctionEval': [ + { + properties: { + 'functionObject': { ref: 7 } + } + } + ] + } + }; + + var exception = null; + var pack = g_client.createPack(); + try { + o3djs.serialization.deserialize(pack, json); + } catch (e) { + exception = e; + } + + g_test.assertEquals('Could not find object with id 7.', exception); +}; + +g_suite.testDeserializesArrayOfReferenceProperty = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.Primitive': [ + { + id: 7 + } + ], + 'o3d.Shape': [ + { + properties: { + 'elements': [{ ref: 7 }] + } + } + ] + } + }; + + var pack = g_client.createPack(); + o3djs.serialization.deserialize(pack, json); + + g_test.assertEquals(2, pack.objects.length); + g_test.assertEquals(1, pack.objects[1]['elements'].length); + g_test.assertEquals(pack.objects[0].clientId, pack.objects[1]['elements'][0].clientId); +}; + +g_suite.testIgnoresMissingProperty = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.Transform': [ + { + properties: { + missing: true + } + } + ] + } + }; + + var pack = g_client.createPack(); + o3djs.serialization.deserialize(pack, json); + + g_test.assertEquals(1, pack.objects.length); + g_test.assertFalse('missing' in pack.objects[0]); +}; + +g_suite.testShouldCallInitializationCallbackIfPresent = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'myname.SpecialClass': [ + { + indexBuffer: {ref: 7} + } + ], + 'o3d.IndexBuffer': [ + { + id: 7 + } + ] + } + }; + + var pack = g_client.createPack(); + var deserializer = o3djs.serialization.createDeserializer(pack, json); + + deserializer.createCallbacks['myname.SpecialClass'] = function( + deserializer, json) { + return deserializer.pack.createObject('o3d.Primitive'); + }; + + deserializer.initCallbacks['myname.SpecialClass'] = function( + deserializer, object, json) { + object.indexBuffer = deserializer.deserializeValue(json.indexBuffer); + }; + + deserializer.run(); + + g_test.assertEquals(2, pack.objects.length); + g_test.assertEquals(pack.objects[1].clientId, pack.objects[0].indexBuffer.clientId); +}; + +g_suite.testShouldIgnoreCallIfMethodIsMissing = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.Primitive': [ + { + calls: [ + ['missingMethod', 1, 2, 3] + ] + } + ] + } + }; + + var pack = g_client.createPack(); + o3djs.serialization.deserialize(pack, json); + + g_test.assertEquals(1, pack.objects.length); +}; + +g_suite.testDeserializesExistingParam = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.Transform': [ + { + params: { + localMatrix: {value: [[1,2,3,4],[5,6,7,8],[8,7,6,5],[4,3,2,1]]} + } + } + ] + } + }; + + var pack = g_client.createPack(); + o3djs.serialization.deserialize(pack, json); + + g_test.assertEquals(1, pack.objects.length); + g_test.assertEquals(4, pack.objects[0].localMatrix[3][0]); +}; + +g_suite.testDeserializesAddedParam = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.Transform': [ + { + params: { + newParam: {'class': 'o3d.ParamFloat', value: 7} + } + } + ] + } + }; + + var pack = g_client.createPack(); + o3djs.serialization.deserialize(pack, json); + + g_test.assertEquals(1, pack.objects.length); + g_test.assertEquals(7, pack.objects[0].getParam('newParam').value); +}; + +g_suite.testBindsParam = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.Matrix4Translation': [ + { + params: { + 'o3d.outputMatrix': {id: 2} + } + }, + { + params: { + 'o3d.inputMatrix': {bind: 2} + } + } + ] + } + }; + + var pack = g_client.createPack(); + o3djs.serialization.deserialize(pack, json); + + g_test.assertEquals(2, pack.objects.length); + g_test.assertEquals(pack.objects[0].getParam('o3d.outputMatrix').clientId, + pack.objects[1].getParam('o3d.inputMatrix').inputConnection.clientId); +}; + +g_suite.testIgnoresMissingOutputs = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.Matrix4Translation': [ + { + params: { + missingParam: {id: 2} + } + } + ] + } + }; + + var pack = g_client.createPack(); + o3djs.serialization.deserialize(pack, json); + + g_test.assertEquals(1, pack.objects.length); + g_test.assertNull(pack.objects[0].getParam('misingParam')); +}; + +g_suite.testExceptionIfCannotBindParam = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.Matrix4Translation': [ + { + params: { + 'o3d.inputMatrix': {bind: 2} + } + } + ] + } + }; + + var pack = g_client.createPack(); + var exception = null; + try { + o3djs.serialization.deserialize(pack, json); + } catch(e) { + exception = e; + } + + g_test.assertEquals('Could not find output param with id 2.', exception); +}; + +g_suite.testCannotBindToMissingOutput = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.Matrix4Translation': [ + { + params: { + missingOutput: {id: 2} + } + }, + { + params: { + 'o3d.inputMatrix': {bind: 2} + } + } + ] + } + }; + + var pack = g_client.createPack(); + var exception = null; + try { + o3djs.serialization.deserialize(pack, json); + } catch(e) { + exception = e; + } + + g_test.assertEquals('Could not find output param with id 2.', exception); +}; + +g_suite.testDeserializesParamArray = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.ParamArray': [ + { + params: [ + {'class': 'o3d.ParamFloat', value: 7}, + {'class': 'o3d.ParamBoolean', value: true} + ] + } + ] + } + }; + + var pack = g_client.createPack(); + o3djs.serialization.deserialize(pack, json); + + g_test.assertEquals(1, pack.objects.length); + var array = pack.objects[0]; + g_test.assertEquals(2, array.length); + g_test.assertEquals(7, array.getParam(0).value); + g_test.assertEquals(true, array.getParam(1).value); +}; + +g_suite.testDeserializesParamArrayWithBindings = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.ParamArray': [ + { + params: [ + {'class': 'o3d.ParamFloat', id: 1, value: 7}, + {'class': 'o3d.ParamBoolean', id: 2, value: true}, + {'class': 'o3d.ParamFloat', id: 3, bind: 1} + ] + } + ] + } + }; + + var pack = g_client.createPack(); + o3djs.serialization.deserialize(pack, json); + + g_test.assertEquals(1, pack.objects.length); + var array = pack.objects[0]; + g_test.assertEquals(3, array.length); + g_test.assertEquals(array.getParam(0).clientId, + array.getParam(2).inputConnection.clientId); +}; + +g_suite.testDeserializerObjectShouldDeserializeIncrementallyWhenRunRepeatedly = function() { + var json = { + version: o3djs.serialization.supportedVersion, + o3d_rootObject_root: {ref: 7}, + objects: { + 'o3d.Transform': [ + { + id: 7, + properties: { + name: 'transform1' + } + }, + { + properties: { + name: 'transform2' + } + } + ] + } + }; + + var pack = g_client.createPack(); + var deserializer = o3djs.serialization.createDeserializer(pack, json); + g_test.assertEquals(0, pack.objects.length); + var running; + running = deserializer.run(1); + g_test.assertEquals(true, running); + g_test.assertEquals(1, pack.objects.length); + running = deserializer.run(1); + g_test.assertEquals(true, running); + g_test.assertEquals(2, pack.objects.length); + running = deserializer.run(1); + g_test.assertEquals(true, running); + g_test.assertEquals(2, pack.objects.length); + running = deserializer.run(1); + g_test.assertEquals(false, running); + g_test.assertEquals(2, pack.objects.length); + + g_test.assertEquals('o3d.Transform', pack.objects[0].className); + g_test.assertEquals('transform1', pack.objects[0].name); + g_test.assertEquals('o3d.Transform', pack.objects[1].className); + g_test.assertEquals('transform2', pack.objects[1].name); + + running = deserializer.run(1); + g_test.assertEquals(false, running); + g_test.assertEquals(2, pack.objects.length); +}; + +g_suite.testDeserializesTexture2DByCallingSpecialCreateFunction = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.Texture2D': [ + { + params: { + myParam: {'class':'o3d.ParamFloat', value: 7} + }, + custom: { + width: 256, + height: 256, + format: 1, + levels: 2, + renderSurfacesEnabled: true + } + } + ] + } + }; + + var pack = g_client.createPack(); + o3djs.serialization.deserialize(pack, json); + + g_test.assertEquals(1, pack.objects.length); + g_test.assertEquals('o3d.Texture2D', pack.objects[0].className); + g_test.assertEquals(256, pack.objects[0].width); + g_test.assertEquals(256, pack.objects[0].height); + g_test.assertEquals(1, pack.objects[0].format); + + var myParam = pack.objects[0].getParam("myParam"); + g_test.assertEquals(7, myParam.value); +}; + +g_suite.testFindsTextureFromArchive = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.Texture2D': [ + { + params: { + 'o3d.uri': { + 'class': 'o3d.ParamString', + value: 'dir/image1.png' + } + } + } + ] + } + }; + + var pack = g_client.createPack(); + var deserializer = o3djs.serialization.createDeserializer(pack, json); + deserializer.archiveInfo = g_archiveInfo; + deserializer.run(); + + g_test.assertEquals(1, pack.objects.length); + g_test.assertEquals('o3d.Texture2D', pack.objects[0].className); + g_test.assertEquals(16, pack.objects[0].width); + g_test.assertEquals(16, pack.objects[0].height); + g_test.assertEquals(5, pack.objects[0].levels); +}; + +g_suite.testExceptionIfCannotFindTexture = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.Texture2D': [ + { + params: { + 'o3d.uri': { + 'class': 'o3d.ParamString', + value: 'dir/missing.png' + } + } + } + ] + } + }; + + var pack = g_client.createPack(); + var deserializer = o3djs.serialization.createDeserializer(pack, json); + deserializer.archiveInfo = g_archiveInfo; + var error = ''; + try { + deserializer.run(); + } catch (e) { + error = e; + } + + g_test.assertEquals('Could not find texture dir/missing.png in the archive', + error); +}; + +g_suite.testDeserializesTextureCUBEByCallingSpecialCreateFunction = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.TextureCUBE': [ + { + params: { + myParam: {'class':'o3d.ParamFloat', value: 7} + }, + custom: { + edgeLength: 256, + format: 1, + levels: 2, + renderSurfacesEnabled: true + } + } + ] + } + }; + + var pack = g_client.createPack(); + o3djs.serialization.deserialize(pack, json); + + g_test.assertEquals(1, pack.objects.length); + g_test.assertEquals('o3d.TextureCUBE', pack.objects[0].className); + g_test.assertEquals(256, pack.objects[0].edgeLength); + g_test.assertEquals(1, pack.objects[0].format); + + var myParam = pack.objects[0].getParam("myParam"); + g_test.assertEquals(7, myParam.value); +}; + + +g_suite.testFindsCUBETextureFromArchive = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.TextureCUBE': [ + { + params: { + 'o3d.uri': { + 'class': 'o3d.ParamString', + value: 'dir/image1.png' + } + } + } + ] + } + }; + + var pack = g_client.createPack(); + var deserializer = o3djs.serialization.createDeserializer(pack, json); + deserializer.archiveInfo = g_archiveInfo; + deserializer.run(); + + g_test.assertEquals(1, pack.objects.length); + g_test.assertEquals('o3d.Texture2D', pack.objects[0].className); + g_test.assertEquals(16, pack.objects[0].width); + g_test.assertEquals(16, pack.objects[0].height); + g_test.assertEquals(5, pack.objects[0].levels); +}; + +g_suite.testExceptionIfCannotFindCUBETexture = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.TextureCUBE': [ + { + params: { + 'o3d.uri': { + 'class': 'o3d.ParamString', + value: 'dir/missing.png' + } + } + } + ] + } + }; + + var pack = g_client.createPack(); + var deserializer = o3djs.serialization.createDeserializer(pack, json); + deserializer.archiveInfo = g_archiveInfo; + var error = ''; + try { + deserializer.run(); + } catch (e) { + error = e; + } + + g_test.assertEquals('Could not find texture dir/missing.png in the archive', + error); +}; + +g_suite.testShouldSetVertexBufferData = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.VertexBuffer': [ + { + custom: { + fields: [7,8,9], + binaryRange: [5310,10620] + } + } + ] + } + }; + + var pack = g_client.createPack(); + var deserializer = o3djs.serialization.createDeserializer(pack, json); + deserializer.archiveInfo = g_archiveInfo; + deserializer.run(); + + g_test.assertEquals(1, pack.objects.length); + var buffer = pack.objects[0]; + g_test.assertEquals(1, buffer.fields.length); + var field = buffer.fields[0]; + g_test.assertEquals('o3d.FloatField', field.className); + g_test.assertEquals(3, field.numComponents); + g_test.assertEquals(12, field.size); +}; + +g_suite.testShouldSetSourceBufferData = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.SourceBuffer': [ + { + custom: { + fields: [7,8,9], + binaryRange: [5310,10620] + } + } + ] + } + }; + + var pack = g_client.createPack(); + var deserializer = o3djs.serialization.createDeserializer(pack, json); + deserializer.archiveInfo = g_archiveInfo; + deserializer.run(); + + g_test.assertEquals(1, pack.objects.length); + var buffer = pack.objects[0]; + g_test.assertEquals(1, buffer.fields.length); + var field = buffer.fields[0]; + g_test.assertEquals('o3d.FloatField', field.className); + g_test.assertEquals(3, field.numComponents); + g_test.assertEquals(12, field.size); +}; + +g_suite.testShouldSetIndexBufferData = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.IndexBuffer': [ + { + custom: { + fields:[7], + binaryRange:[9618,10092] + } + } + ] + } + }; + + var pack = g_client.createPack(); + var deserializer = o3djs.serialization.createDeserializer(pack, json); + deserializer.archiveInfo = g_archiveInfo; + deserializer.run(); + + g_test.assertEquals(1, pack.objects.length); + var buffer = pack.objects[0]; + g_test.assertEquals(1, buffer.fields.length); + var field = buffer.fields[0]; + g_test.assertEquals('o3d.UInt32Field', field.className); + g_test.assertEquals(1, field.numComponents); + g_test.assertEquals(4, field.size); + g_test.assertArrayEquals([0, 1, 2, 0, 2], field.getAt(0, 5)); +}; + +g_suite.testShouldSetCurveWithKeys = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.Curve': [ + { + custom: { + binaryRange: [358,716] + } + } + ] + } + }; + + var pack = g_client.createPack(); + var deserializer = o3djs.serialization.createDeserializer(pack, json); + deserializer.archiveInfo = g_archiveInfo; + deserializer.run(); + + g_test.assertEquals(1, pack.objects.length); + var keys = pack.objects[0].keys; + g_test.assertEquals(14, keys.length); +}; + +g_suite.testShouldSetSkinEvalStreams = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.SkinEval': [ + { + custom: { + vertexStreams: [ + { + stream: { + field: 8, + startIndex: 4, + semantic: 1, + semanticIndex: 2 + } + } + ] + } + } + ], + 'o3d.SourceBuffer': [ + { + id: 7, + custom: { + fields: [8,9,10], + binaryRange: [5310,10620] + } + } + ] + } + }; + + var pack = g_client.createPack(); + var deserializer = o3djs.serialization.createDeserializer(pack, json); + deserializer.archiveInfo = g_archiveInfo; + deserializer.run(); + + g_test.assertEquals(2, pack.objects.length); + var stream = pack.objects[0].vertexStreams[0]; + var field = pack.objects[1].fields[0]; + g_test.assertEquals(field.clientId, stream.field.clientId); + g_test.assertEquals(4, stream.startIndex); + g_test.assertEquals(1, stream.semantic); + g_test.assertEquals(2, stream.semanticIndex); +}; + +g_suite.testShouldSetStreamBankStreams = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.StreamBank': [ + { + custom: { + vertexStreams: [ + { + stream: { + field: 8, + startIndex: 4, + semantic: 1, + semanticIndex: 2 + } + } + ] + } + } + ], + 'o3d.VertexBuffer': [ + { + id: 7, + custom: { + fields: [8], + binaryRange: [5310,10620] + } + } + ] + } + }; + + var pack = g_client.createPack(); + var deserializer = o3djs.serialization.createDeserializer(pack, json); + deserializer.archiveInfo = g_archiveInfo; + deserializer.run(); + + g_test.assertEquals(2, pack.objects.length); + var stream = pack.objects[0].vertexStreams[0]; + var field = pack.objects[1].fields[0]; + g_test.assertEquals(field.clientId, stream.field.clientId); + g_test.assertEquals(4, stream.startIndex); + g_test.assertEquals(1, stream.semantic); + g_test.assertEquals(2, stream.semanticIndex); +}; + +g_suite.testShouldSetAndBindStreamBankStreams = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.SkinEval': [ + { + id: 7, + custom: { + vertexStreams: [ + { + stream: { + field: 9, + startIndex: 4, + semantic: 1, + semanticIndex: 2 + } + } + ] + } + } + ], + 'o3d.SourceBuffer': [ + { + id: 8, + custom: { + fields: [9], + binaryRange: [5310,10620] + } + } + ], + 'o3d.StreamBank': [ + { + custom: { + vertexStreams: [ + { + stream: { + field: 11, + startIndex: 4, + semantic: 1, + semanticIndex: 2 + }, + bind: 7 + } + ] + } + } + ], + 'o3d.VertexBuffer': [ + { + id: 10, + custom: { + fields: [11], + binaryRange: [5310,10620] + } + } + ] + } + }; + + var pack = g_client.createPack(); + var deserializer = o3djs.serialization.createDeserializer(pack, json); + deserializer.archiveInfo = g_archiveInfo; + deserializer.run(); + + g_test.assertEquals(4, pack.objects.length); + g_test.assertTrue(pack.objects[2].unbindStream(1, 2)); +}; + +g_suite.testShouldSetAndBindSkinEvalStreams = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.SkinEval': [ + { + id: 7, + custom: { + vertexStreams: [ + { + stream: { + field: 9, + startIndex: 4, + semantic: 1, + semanticIndex: 2 + } + } + ] + } + }, + { + id: 14, + custom: { + vertexStreams: [ + { + stream: { + field: 11, + startIndex: 4, + semantic: 1, + semanticIndex: 2 + }, + bind: 7 + } + ] + } + } + ], + 'o3d.SourceBuffer': [ + { + id: 8, + custom: { + fields: [9], + binaryRange: [5310,10620] + } + }, + { + id: 10, + custom: { + fields: [11], + binaryRange: [5310,10620] + } + } + ] + } + }; + + var pack = g_client.createPack(); + var deserializer = o3djs.serialization.createDeserializer(pack, json); + deserializer.archiveInfo = g_archiveInfo; + deserializer.run(); + + g_test.assertEquals(4, pack.objects.length); + g_test.assertTrue(pack.objects[1].unbindStream(1, 2)); +}; + +g_suite.testShouldLoadEffectShaderFromArchive = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.Effect': [ + { + params: { + 'o3d.uri': { + 'class': 'o3d.ParamString', + value: 'dir/solid-color.shader' + } + } + } + ] + } + }; + + var pack = g_client.createPack(); + var deserializer = o3djs.serialization.createDeserializer(pack, json); + deserializer.archiveInfo = g_archiveInfo; + deserializer.run(); + + g_test.assertEquals(1, pack.objects.length); + var effect = pack.objects[0]; + g_test.assertEquals('o3d.Effect', effect.className); + g_test.assertEquals('//', effect.source.substring(0, 2)); +}; + +g_suite.testExceptionIfCannotLoadShaderFromArchive = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.Effect': [ + { + params: { + 'o3d.uri': { + 'class': 'o3d.ParamString', + value: 'dir/image1.png' + } + } + } + ] + } + }; + + var pack = g_client.createPack(); + var deserializer = o3djs.serialization.createDeserializer(pack, json); + deserializer.archiveInfo = g_archiveInfo; + var error = ''; + try { + deserializer.run(); + } catch (e) { + error = e; + } + + g_test.assertEquals('Cannot load shader dir/image1.png in archive.', error); +}; + +g_suite.testShouldSetSkinData = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.Skin': [ + { + custom: { + binaryRange: [32724,34584] + } + } + ] + } + }; + + var pack = g_client.createPack(); + var deserializer = o3djs.serialization.createDeserializer(pack, json); + deserializer.archiveInfo = g_archiveInfo; + deserializer.run(); + + g_test.assertEquals(1, pack.objects.length); + var skin = pack.objects[0]; + g_test.assertEquals(79, skin.influences.length); + g_test.assertEquals(2, skin.influences[0].length); + g_test.assertArrayEquals([2, 1], skin.influences[0]); +}; + +g_suite.testExceptionIfEffectShaderCannotBeFound = function() { + var json = { + version: o3djs.serialization.supportedVersion, + objects: { + 'o3d.Effect': [ + { + params: { + 'o3d.uri': { + 'class': 'o3d.ParamString', + value: 'dir/missing.shader' + } + } + } + ] + } + }; + + var pack = g_client.createPack(); + var deserializer = o3djs.serialization.createDeserializer(pack, json); + deserializer.archiveInfo = g_archiveInfo; + var error = ''; + try { + deserializer.run(); + } catch (e) { + error = e; + } + + g_test.assertEquals( + 'Cannot find shader dir/missing.shader in archive.', + error); +}; + +function initStep3(archiveInfo, exception) { + window.g_archiveInfo = archiveInfo; + window.g_testResult = g_test.runTests(g_suite); +} + +function initStep2(clientElements) { + window.g_test = o3djs.test; + window.g_plugin = clientElements[0]; + window.g_client = clientElements[0].client; + window.g_pack = g_client.createPack(); + window.g_client.clearErrorCallback(); + o3djs.io.loadArchive(g_pack, 'assets/archive.o3dtgz', initStep3); +}; + +window.onload = function() { + o3djs.util.makeClients(initStep2); +}; + +</script> +</body> +</html> diff --git a/o3d/tests/selenium/tests/test-test.html b/o3d/tests/selenium/tests/test-test.html new file mode 100644 index 0000000..06d6a0d --- /dev/null +++ b/o3d/tests/selenium/tests/test-test.html @@ -0,0 +1,368 @@ +<!-- +Copyright 2009, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title> +Unit Testing library tests +</title> +</head> +<body> +<h1>Unit Testing library tests</h1> +This tests the operation of the unit testing library. +<br/> +<script type="text/javascript" + src="../../../samples/o3djs/base.js"></script> +<script type="text/javascript"> + +o3djs.require('o3djs.test'); + +function MockReporter() { + this.reportPass = function(testName) { + this.passName = testName; + } + this.reportFail = function(testName, message) { + this.failName = testName; + this.failMessage = message; + } + this.reportSummary = function(passCount, failCount) { + this.passCount = passCount; + this.failCount = failCount; + } +}; + +var g_suite = {}; + +g_suite.testRunsFunctionsWithTestPrefix = function() { + var ran = false; + var tests = { + testFoo: function() { + ran = true; + } + }; + var reporter = new MockReporter(); + g_test.runTests(tests, reporter); + g_test.assertTrue(ran); + g_test.assertEquals('testFoo', reporter.passName); + g_test.assertEquals('undefined', typeof(reporter.failName)); +}; + +g_suite.testDoesNotRunFunctionsWithoutTestPrefix = function() { + var ran = false; + var tests = { + notATest: function() { + ran = true; + } + }; + var reporter = new MockReporter(); + g_test.runTests(tests, reporter); + g_test.assertFalse(ran); + g_test.assertEquals('undefined', typeof(reporter.passName)); + g_test.assertEquals('undefined', typeof(reporter.failName)); +}; + +g_suite.testDoesNotRunValuesThatAreNotFunctions = function() { + var tests = { + testFoo: 7 + }; + var reporter = new MockReporter(); + g_test.runTests(tests, reporter); + g_test.assertEquals('undefined', typeof(reporter.passName)); + g_test.assertEquals('undefined', typeof(reporter.failName)); +}; + +g_suite.testReportsNumberOfPassingTests = function() { + var tests = { + testFoo: function() { + }, + testBar: function() { + }, + testBaz: function() { + assertTrue(false); + } + }; + var reporter = new MockReporter(); + g_test.runTests(tests, reporter); + g_test.assertEquals(2, reporter.passCount); + g_test.assertEquals(1, reporter.failCount); +}; + +g_suite.testReturnsTrueIfAllTestsPass = function() { + var tests = { + testFoo: function() { + }, + testBar: function() { + } + }; + var reporter = new MockReporter(); + g_test.assertTrue(g_test.runTests(tests, reporter)); +}; + +g_suite.testReturnsFalseIfAnyTestFails = function() { + var tests = { + testFoo: function() { + }, + testBar: function() { + g_test.assertTrue(false); + } + }; + var reporter = new MockReporter(); + g_test.assertFalse(g_test.runTests(tests, reporter)); +}; + +g_suite.testAssertTrueDoesNotAssertForTrueValue = function() { + g_test.assertTrue(true); +}; + +g_suite.testAssertTrueAssertsForFalseValue = function() { + var tests = { + testFoo: function() { + g_test.assertTrue(false); + } + }; + var reporter = new MockReporter(); + g_test.runTests(tests, reporter); + g_test.assertEquals('undefined', typeof(reporter.passName)); + g_test.assertEquals('testFoo', reporter.failName); + g_test.assertEquals( + 'assertTrue failed for false', + reporter.failMessage); +}; + +g_suite.testAssertFalseDoesNotAssertForFalseValue = function() { + g_test.assertFalse(false); +}; + +g_suite.testAssertFalseAssertsForTrueValue = function() { + var tests = { + testFoo: function() { + g_test.assertFalse(true); + } + }; + var reporter = new MockReporter(); + g_test.runTests(tests, reporter); + g_test.assertEquals('undefined', typeof(reporter.passName)); + g_test.assertEquals('testFoo', reporter.failName); + g_test.assertEquals( + 'assertFalse failed for true', + reporter.failMessage); +}; + +g_suite.testAssertNullDoesNotAssertForNullValue = function() { + g_test.assertNull(null); +}; + +g_suite.testAssertNullAssertsForNonNullValue = function() { + var tests = { + testFoo: function() { + g_test.assertNull(undefined); + } + }; + var reporter = new MockReporter(); + g_test.runTests(tests, reporter); + g_test.assertEquals('undefined', typeof(reporter.passName)); + g_test.assertEquals('testFoo', reporter.failName); + g_test.assertEquals( + 'assertNull failed for undefined', + reporter.failMessage); +}; + +g_suite.testAssertEqualsDoesNotAssertForEqualValue = function() { + g_test.assertEquals(7, 7); +}; + +g_suite.testAssertEqualsAssertsForUnequalValue = function() { + var tests = { + testFoo: function() { + g_test.assertEquals(6, 7); + } + }; + var reporter = new MockReporter(); + g_test.runTests(tests, reporter); + g_test.assertEquals('undefined', typeof(reporter.passName)); + g_test.assertEquals('testFoo', reporter.failName); + g_test.assertEquals( + 'assertEquals failed: expected 6 but got 7', + reporter.failMessage); +}; + +g_suite.testStringValuesAreReportedInQuotes = function() { + var tests = { + testFoo: function() { + g_test.assertEquals('a', 'b'); + } + }; + var reporter = new MockReporter(); + g_test.runTests(tests, reporter); + g_test.assertEquals('undefined', typeof(reporter.passName)); + g_test.assertEquals('testFoo', reporter.failName); + g_test.assertEquals( + 'assertEquals failed: expected "a" but got "b"', + reporter.failMessage); +}; + +g_suite.testObjectsWithDifferentIdentityAreNotEqual = function() { + var tests = { + testFoo: function() { + g_test.assertEquals({a: 7, b: 8, f: function() {}}, + {a: 7, b: 8, f: function() {}}); + } + }; + var reporter = new MockReporter(); + g_test.runTests(tests, reporter); + g_test.assertEquals('undefined', typeof(reporter.passName)); + g_test.assertEquals('testFoo', reporter.failName); + g_test.assertEquals( + 'assertEquals failed: expected {a: 7, b: 8} but got {a: 7, b: 8}', + reporter.failMessage); +}; + +g_suite.testAssertCloseDoesNotAssertForEqualValue = function() { + g_test.assertClose(7, 7); +}; + +g_suite.testAssertCloseDoesNotAssertForSlightlySmallerActual = function() { + g_test.assertClose(7, 6.9991); +}; + +g_suite.testAssertCloseDoesNotAssertForSlightlyLargerActual = function() { + g_test.assertClose(7, 7.0009); +}; + +g_suite.testAssertCloseAssertsForValueOutsideThreshold= function() { + var tests = { + testFoo: function() { + g_test.assertClose(7, 7.0015); + } + }; + var reporter = new MockReporter(); + g_test.runTests(tests, reporter); + g_test.assertEquals('undefined', typeof(reporter.passName)); + g_test.assertEquals('testFoo', reporter.failName); + g_test.assertEquals( + 'assertClose failed: expected 7 but got 7.0015', + reporter.failMessage); +}; +g_suite.testAssertArrayEqualsDoesNotAssertForEqualArrays = function() { + g_test.assertArrayEquals([1, 2, 3], [1, 2, 3]); +}; + +g_suite.testAssertArrayEqualsAssertsForNonArrayExpectedValue = function() { + var tests = { + testFoo: function() { + g_test.assertArrayEquals(7, [1, 2, 3]); + } + }; + var reporter = new MockReporter(); + g_test.runTests(tests, reporter); + g_test.assertEquals('undefined', typeof(reporter.passName)); + g_test.assertEquals('testFoo', reporter.failName); + g_test.assertEquals( + 'assertArrayEquals failed: expected value 7 is not an array', + reporter.failMessage); +} + +g_suite.testAssertArrayEqualsAssertsForNonArrayActualValue = function() { + var tests = { + testFoo: function() { + g_test.assertArrayEquals([1, 2], 7); + } + }; + var reporter = new MockReporter(); + g_test.runTests(tests, reporter); + g_test.assertEquals('undefined', typeof(reporter.passName)); + g_test.assertEquals('testFoo', reporter.failName); + g_test.assertEquals( + 'assertArrayEquals failed: actual value 7 is not an array', + reporter.failMessage); +}; + +g_suite.testAssertArrayEqualsAssertsForArraysOfDifferingLength = function() { + var tests = { + testFoo: function() { + g_test.assertArrayEquals([1, 2], [1, 2, 3]); + } + }; + var reporter = new MockReporter(); + g_test.runTests(tests, reporter); + g_test.assertEquals('undefined', typeof(reporter.passName)); + g_test.assertEquals('testFoo', reporter.failName); + g_test.assertEquals( + 'assertArrayEquals failed: expected [1, 2] but got [1, 2, 3]', + reporter.failMessage); +}; + +g_suite.testAssertArrayEqualsAssertsForArraysWithDifferingElement = function() { + var tests = { + testFoo: function() { + g_test.assertArrayEquals([3, 2, 1], [1, 2, 3]); + } + }; + var reporter = new MockReporter(); + g_test.runTests(tests, reporter); + g_test.assertEquals('undefined', typeof(reporter.passName)); + g_test.assertEquals('testFoo', reporter.failName); + g_test.assertEquals( + 'assertArrayEquals failed: expected [3, 2, 1] but got [1, 2, 3]', + reporter.failMessage); +}; + +g_suite.testAssertArrayEqualsDoesNotAssertForEqual2DArrays = function() { + g_test.assertArrayEquals([[1, 2, 3]], [[1, 2, 3]]); +}; + +g_suite.testAssertArrayEqualsAssertsFor2DArraysWithDifferingElement = + function() { + var tests = { + testFoo: function() { + g_test.assertArrayEquals([[3, 2, 1]], [[1, 2, 3]]); + } + }; + var reporter = new MockReporter(); + g_test.runTests(tests, reporter); + g_test.assertEquals('undefined', typeof(reporter.passName)); + g_test.assertEquals('testFoo', reporter.failName); + g_test.assertEquals( + 'assertArrayEquals failed: expected [[3, 2, 1]] but got [[1, 2, 3]]', + reporter.failMessage); +}; + +window.onload = function() { + window.g_test = o3djs.test; + window.g_testResult = g_test.runTests(g_suite); +}; + +</script> +</body> +</html> diff --git a/o3d/tests/selenium/tests/type-test.html b/o3d/tests/selenium/tests/type-test.html new file mode 100644 index 0000000..fe88c72 --- /dev/null +++ b/o3d/tests/selenium/tests/type-test.html @@ -0,0 +1,166 @@ +<!-- +Copyright 2009, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + +<!-- +A Selenium test to make sure various math types convert. +--> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title> +Type Test +</title> +<!-- Our javascript code --> +<script type="text/javascript" src="../../../samples/o3djs/base.js"></script> + +<script type="text/javascript"> +o3djs.require('o3djs.util'); +o3djs.require('o3djs.math'); + +window.onload = init; + +// global variables +var g_o3d; +var g_math; +var g_client; +var g_pack; +var g_testResult; + +function compare3(object, x, y, z) { + return object[0] == x && + object[1] == y && + object[2] == z; +} + +function compare4(object, x, y, z, w) { + return object[0] == x && + object[1] == y && + object[2] == z && + object[3] == w; +} + +function compareArrays(array1, array2) { + if (array1.length != array2.length) { + return false; + } + for (var ii = 0; ii < array1.length; ++ii) { + if (array1[ii] !== array2[ii]) { + return false; + } + } + return true; +} + +/** + * Creates the client area. + */ +function init() { + o3djs.util.makeClients(initStep2); +} + +/** + * Initializes g_o3d, loads the effect, and draws the sphere. + * @param {Array} clientElements Array of o3d object elements. + */ +function initStep2(clientElements) { + // Initialize global variables and libraries. + var o3d = clientElements[0]; + g_o3d = o3d.o3d; + g_math = o3djs.math; + g_client = o3d.client; + + // Create a g_pack to manage our resources/assets + g_pack = g_client.createPack(); + + var good = true; + // we shouldn't get an error while we're testing any of these. + g_client.setErrorCallback(function(msg) { good = false; }); + + var transform = g_pack.createObject('Transform'); + var paramFloat3 = transform.createParam('f3', 'ParamFloat3'); + var paramFloat4 = transform.createParam('f4', 'ParamFloat4'); + var float3; + var float4; + var test = 0; + + // --- float3 --- + + // Check that we can set a ParamFloat3 to an array + if (good) { + test++; + paramFloat3.value = [1, 2, 3]; + good = good && compare3(paramFloat3.value, 1, 2, 3); + } + + // Check that we can get an array from a ParamFloat3 + if (good) { + test++; + float3 = paramFloat3.value; + good = good && compare3(float3, 1, 2, 3); + } + + // --- float4 --- + + // Check that we can set a ParamFloat4 to an array + if (good) { + test++; + paramFloat4.value = [1, 2, 3, 4]; + good = good && compare4(paramFloat4.value, 1, 2, 3, 4); + } + + // Check that we can get an array from a ParamFloat4 + if (good) { + test++; + float4 = paramFloat4.value; + good = good && compare4(float4, 1, 2, 3, 4); + } + + document.getElementById('testStatus').innerHTML = "Finished"; + document.getElementById('testResults').innerHTML = + good ? "Passed" : ("Failed: at test# " + test); + g_testResult = good; +} + +</script> +</head> +<body> +<h1>Type Test</h1> +<table> +<tr><td>Tests:</td><td><span id="testStatus">Running</span></td></td> +<tr><td>Results:</td><td><span id="testResults">---</span></td></td> +</table> +<!-- Start of g_o3d plugin --> +<div id="o3d" style="width: 100px; height: 100px;"></div> +<!-- End of g_o3d plugin --> +</body> +</html> diff --git a/o3d/tests/selenium/tests/util-test.html b/o3d/tests/selenium/tests/util-test.html new file mode 100644 index 0000000..9785ed3 --- /dev/null +++ b/o3d/tests/selenium/tests/util-test.html @@ -0,0 +1,111 @@ +<!-- +Copyright 2009, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title> +Util Test +</title> +</head> +<body> +<h1>Util Test</h1> +This tests util.js. +<br/> + +<!-- Start of O3D plugin --> +<div id="o3d" style="width: 32px; height: 32px;"></div> +<!-- End of O3D plugin --> + +<script type="text/javascript" + src="../../../samples/o3djs/base.js"></script> +<script type="text/javascript"> + +o3djs.require('o3djs.test'); +o3djs.require('o3djs.util'); + +g_suite = {}; + +function add(a, b) { + return a + b; +} + +g_suite.testCanCurryAFunctionFixingNoArguments = function() { + var newAdd = o3djs.util.curry(add); + g_test.assertEquals(3, newAdd(1, 2)); +} + +g_suite.testCanCurryAFunctionFixingSomeArguments = function() { + var increment = o3djs.util.curry(add, 1); + g_test.assertEquals(3, increment(2)); +} + +g_suite.testCanCurryAFunctionFixingAllArguments = function() { + var three = o3djs.util.curry(add, 1, 2); + g_test.assertEquals(3, three()); +} + +g_suite.testLeavesAbsoluteURIUnchanged = function() { + g_test.assertEquals( + 'http://www.domain.org/foo/bar.html', + o3djs.util.toAbsoluteUri('http://www.domain.org/foo/bar.html')); +}; + +g_suite.testAddsBaseURIToRelativeURI = function() { + g_test.assertEquals( + g_baseUri + '/foo/bar.html', + o3djs.util.toAbsoluteUri('foo/bar.html')); +}; + +g_suite.testStripsDotDotFromAbsoluteURI = function() { + g_test.assertEquals( + g_baseUri + '/bing/foo/baz.html', + o3djs.util.toAbsoluteUri('bing/foo/bar/../../foo/baz.html')); +}; + +function initStep2(clientElements) { + g_test = o3djs.test; + g_plugin = clientElements[0]; + g_baseUri = document.location.toString(); + var lastSlash = g_baseUri.lastIndexOf('/'); + g_baseUri = g_baseUri.substring(0, lastSlash); + g_testResult = g_test.runTests(g_suite); +}; + +window.onload = function() { + o3djs.util.makeClients(initStep2); +}; + +</script> +</body> +</html> diff --git a/o3d/tests/selenium/tests/v8-test.html b/o3d/tests/selenium/tests/v8-test.html new file mode 100644 index 0000000..fa8173f --- /dev/null +++ b/o3d/tests/selenium/tests/v8-test.html @@ -0,0 +1,772 @@ +<!-- +Copyright 2009, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title> +V8 Test +</title> +</head> +<body> +<h1>V8 / ActiveX Bridge Tests</h1> +This tests V8/NPAPI interoperation and the ActiveX bridge. +<br/> + +<!-- Start of O3D plugin --> +<div id="o3d" style="width: 32px; height: 32px;"></div> +<!-- End of O3D plugin --> + +<script type="text/javascript" + src="../../../samples/o3djs/base.js"></script> +<script type="text/javascript"> + +o3djs.require('o3djs.test'); +o3djs.require('o3djs.util'); +o3djs.require('o3djs.math'); + +var isChrome = navigator.userAgent.indexOf('Chrome') != -1; +var isSafari = !isChrome && navigator.userAgent.indexOf('Safari') != -1; +var isFirefox2 = navigator.userAgent.indexOf('Firefox/2.') != -1; +var isFirefox = navigator.userAgent.indexOf('Firefox') != -1; +var isInternetExplorer = navigator.userAgent.indexOf('Internet Explorer' != -1); + +var g_suite = {}; + +g_suite.testEvaluatesUndefinedExpression = function() { + g_test.assertEquals(undefined, window.g_plugin.eval('undefined')); +}; + +g_suite.testEvaluatesNullExpression = function() { + g_test.assertEquals(null, window.g_plugin.eval('null')); +}; + +g_suite.testEvaluatesDoubleExpression = function() { + g_test.assertEquals(4.5, window.g_plugin.eval('2.25+2.25')); +}; + +g_suite.testEvaluatesInt32Expression = function() { + g_test.assertEquals(4, window.g_plugin.eval('2+2')); +}; + +g_suite.testEvaluatesBooleanExpression = function() { + g_test.assertTrue(window.g_plugin.eval('true || true')); +}; + +g_suite.testEvaluatesStringExpression = function() { + g_test.assertEquals('ab', window.g_plugin.eval('"a" + "b"')); +}; + +g_suite.testWrapsAndUnwrapsV8ObjectsAndPreservesIdentity = function() { + var a = window.g_plugin.eval('var a = {}; a'); + var v8f = window.g_plugin.eval('function(x) { return a === x; }'); + g_test.assertTrue(v8f(a)); +}; + +g_suite.testBrowserConsidersTheSamePluginToBeTheSame = function() { + g_test.assertEquals(g_plugin, g_plugin); +}; + +g_suite.testBrowserConsidersTheSameNPObjectReturnedMultipleTimesToBeTheSame = + function() { + // http://code.google.com/p/chromium/issues/detail?id=5751 + if (!isChrome && !isSafari) { + g_test.assertEquals(g_plugin.client, g_plugin.client); + } +}; + +g_suite.testBrowserConsidersTheSameV8ObjectReturnedMultipleTimesToBeTheSame = + function() { + // http://code.google.com/p/chromium/issues/detail?id=5751 + if (!isChrome && !isSafari) { + window.g_plugin.eval('var a = {};'); + var obj1 = window.g_plugin.eval('a'); + var obj2 = window.g_plugin.eval('a'); + g_test.assertEquals(obj1, obj2); + } +}; + +g_suite.testTypeofV8ObjectInBrowserIsObject = function() { + var a = window.g_plugin.eval('({})'); + if (!isSafari) { + g_test.assertEquals('object', typeof(a)); + } else { + // Safari thinks its a function! + g_test.assertEquals('function', typeof(a)); + } +}; + +g_suite.testTypeofV8FunctionInBrowserIsFunction = function() { + var v8f = window.g_plugin.eval('function() {}'); + g_test.assertEquals('function', typeof(v8f)); +}; + +g_suite.testV8FunctionIsInstanceOfFunctionInBrowser = function() { + var v8f = window.g_plugin.eval('function(x) { return typeof(x); }'); + g_test.assertTrue(v8f instanceof Function); +}; + +g_suite.testV8FunctionKeepsIdentityWhenPassedBackIntoV8 = function() { + var v8f = window.g_plugin.eval( + 'g_originalFunction = function(x) { return typeof(x); }'); + var comparer = window.g_plugin.eval( + 'function(func) { return func === g_originalFunction; }'); + g_test.assertTrue(comparer(v8f)); +}; + +g_suite.testBrowserCanInvokeV8Functions = function() { + var v8f = window.g_plugin.eval('function(x) { return x; }'); + g_test.assertEquals(2, v8f(2)); +}; + +g_suite.testBrowserCanInvokeV8Constructors = function() { + // http://code.google.com/p/chromium/issues/detail?id=3285 + if (!isChrome && !isSafari && !isFirefox2) { + var v8f = window.g_plugin.eval('function(x) { this.p = x; }'); + var obj = new v8f(2); + g_test.assertEquals(2, obj.p); + } +}; + +g_suite.testBrowserCalledV8ConstructorsReturnDistinctObjects = function() { + // http://code.google.com/p/chromium/issues/detail?id=3285 + if (!isChrome && !isSafari && !isFirefox2) { + var v8f = window.g_plugin.eval('function(x) { this.p = x; }'); + var obj1 = new v8f(2); + var obj2 = new v8f(3); + g_test.assertFalse(obj1 === obj2); + } +}; + +g_suite.testBrowserCanGetV8Properties = function() { + var a = window.g_plugin.eval('({ p : 123 })'); + g_test.assertEquals(123, a.p); +}; + +g_suite.testBrowserCanSetV8Properties = function() { + var a = window.g_plugin.eval('({ p : 123 })'); + a.p = 321; + g_test.assertEquals(321, a.p); +}; + +g_suite.testBrowserCanGetV8ArrayElements = function() { + var a = window.g_plugin.eval('([1, 2, 3])'); + g_test.assertEquals(2, a[1]); +}; + +g_suite.testBrowserCanGetV8ArrayLength = function() { + var a = window.g_plugin.eval('([1, 2, 3])'); + g_test.assertEquals(3, a.length); +}; + +g_suite.testBrowserCanSetV8ArrayElements = function() { + var a = window.g_plugin.eval('([1, 2, 3])'); + a[1] = 7; + g_test.assertEquals(7, a[1]); +}; + +g_suite.testBrowserCanSetV8ArrayLength = function() { + var a = window.g_plugin.eval('([1, 2, 3])'); + a.length = 10; + g_test.assertEquals(10, a.length); +}; + +g_suite.testBrowserCanIterateOverV8Array = function() { + // Chrome bug: http://code.google.com/p/chromium/issues/detail?id=5743 + if (!isChrome && !isFirefox2) { + var a = window.g_plugin.eval('([1, 2, 3])'); + var total = 0; + for (var i in a) { + total += a[i]; + } + g_test.assertEquals(6, total); + } +}; + +g_suite.testBrowserCanQueryV8Properties = function() { + var a = window.g_plugin.eval('({ p : 123 })'); + g_test.assertTrue('p' in a); + g_test.assertFalse('q' in a); + g_test.assertTrue(a.hasOwnProperty('p')); + g_test.assertFalse(a.hasOwnProperty('q')); +}; + +g_suite.testBrowserCanQueryV8PropertiesThatAreUndefined = function() { + var a = window.g_plugin.eval('({ p : undefined })'); + g_test.assertTrue('p' in a); +}; + +g_suite.testBrowserCanRemoveV8Properties = function() { + // Firefox does not forward property deletions from the browser + // through the NPAPI. Bug: + // https://bugzilla.mozilla.org/show_bug.cgi?id=470291 + // Neither does Chrome: + // http://code.google.com/p/chromium/issues/detail?id=5746 + if (!isChrome && !isSafari && !isFirefox) { + var a = window.g_plugin.eval('({ p : 123 })'); + g_test.assertTrue(delete a.p); + g_test.assertFalse('p' in a); + } +}; + +g_suite.testBrowserCanInvokeV8Methods = function() { + var obj = window.g_plugin.eval( + 'function C() { this.f = 7; this.m = function() { return this.f; } } new C()'); + g_test.assertEquals(7, obj.m()); +}; + +g_suite.testBrowserCanEnumerateV8Properties = function() { + // Chrome bug: http://code.google.com/p/chromium/issues/detail?id=5743 + if (!isChrome && !isFirefox2) { + var a = window.g_plugin.eval('var a = { p : 123 }; a[1] = 321; a'); + all = ""; + for (m in a) { + all += m; + } + + // The EcmaScript spec says the order property names are returned is + // implementation dependent. + g_test.assertTrue('1p' === all || 'p1' === all); + } +}; + +g_suite.testStringValueOfV8ObjectInBrowserIsDefault = function() { + var a = window.g_plugin.eval('({})'); + g_test.assertEquals('[object Object]', a.toString()); +}; + +g_suite.testStringValueOfV8ObjectInBrowserCanBeOverriden = function() { + var a = window.g_plugin.eval('({ toString: function() { return "foo"; } })'); + g_test.assertEquals('foo', a.toString()); +}; + +g_suite.testV8SeesSameBrowserObjectAsEqualToItself = function() { + if (!isSafari && !isChrome) { + var v8f = window.g_plugin.eval('function(a, b) { return a === b; }'); + var obj = {}; + g_test.assertTrue(v8f(obj, obj)); + } +}; + +g_suite.testTypeofBrowserObjectInV8IsObject = function() { + var v8f = window.g_plugin.eval('function(x) { return typeof(x); }'); + g_test.assertEquals('object', v8f({})); +}; + +// I put in this test because the V8 bridge code uses the absence of +// a call property as an early out test when determining whether a +// browser object is a function or not. +g_suite.testTypeofBrowserObjectInV8IsObjectEvenIfItHasACallProperty = + function() { + var v8f = window.g_plugin.eval('function(x) { return typeof(x); }'); + g_test.assertEquals('object', v8f({ call: {} })); +}; + +g_suite.testTypeofBrowserFunctionInV8IsFunction = function() { + var v8f = window.g_plugin.eval('function(x) { return typeof(x); }'); + g_test.assertEquals('function', v8f(function() {})); +}; + +g_suite.testV8CanInvokeBrowserFunctions = function() { + var v8f = window.g_plugin.eval('function(f) { return f(); }'); + var f = function() { return 12; }; + g_test.assertEquals(12, v8f(f)); +}; + +g_suite.testV8ReceivesExceptionOnInvokingUndefinedFunction = function() { + var v8f = window.g_plugin.eval( + 'function(f) { try { f(); } catch(e) { return e; } }'); + g_test.assertEquals("TypeError: undefined is not a function", + v8f(undefined).toString()); +}; + +g_suite.testV8CanInvokeBrowserConstructor = function() { + window.Constructor = function(x) { this.p = x; }; + var obj = window.g_plugin.eval('new Constructor(7)'); + g_test.assertEquals(7, obj.p); +}; + +g_suite.testV8ReceivesExceptionOnInvokingUndefinedConstructor = function() { + var v8f = window.g_plugin.eval( + 'function(f) { try { new f(); } catch(e) { return e; } }'); + g_test.assertEquals("TypeError: undefined is not a constructor", + v8f(undefined).toString()); +}; + +g_suite.testV8CanGetConstructorFromBrowserObject = function() { + window.Constructor = function(x) { this.p = x; }; + var obj = window.g_plugin.eval('new Constructor(7)'); + g_test.assertTrue(obj.constructor === window.Constructor); +}; + +g_suite.testV8CanGetBrowserProperties = function() { + var a = { p: 123 }; + var v8f = window.g_plugin.eval('function(x) { return x.p; }'); + g_test.assertEquals(123, v8f(a)); +}; + +g_suite.testV8ReceivesExceptionOnGettingPropertyFromUndefined = function() { + var v8f = window.g_plugin.eval( + 'function(x) { try { return x.p; } catch(e) { return e; } }'); + g_test.assertEquals("TypeError: Cannot read property 'p' of undefined", + v8f(undefined).toString()); +}; + +g_suite.testV8CodeReceivesUndefinedIfGettingBrowserPropertyFails = function() { + var a = window.g_plugin.eval('plugin.nonExistentProperty'); + g_test.assertEquals(undefined, a); +}; + +g_suite.testV8CanSetBrowserProperties = function() { + var a = { p: 123 }; + var v8f = window.g_plugin.eval('function(x) { x.p = 321; }'); + v8f(a); + g_test.assertEquals(321, a.p); +}; + +g_suite.testV8CanGetBrowserArrayElements = function() { + var a = [1, 2, 3]; + var v8f = window.g_plugin.eval('function(x) { return x[1]; }'); + g_test.assertEquals(2, v8f(a)); +}; + +g_suite.testV8CodeReceivesUndefinedIfGettingBrowserNonExistentArrayElement = + function() { + var a = window.g_plugin.eval('plugin[17]'); + g_test.assertEquals(undefined, a); +}; + +g_suite.testV8CanGetBrowserArrayLength = function() { + var a = [1, 2, 3]; + var v8f = window.g_plugin.eval('function(x) { return x.length; }'); + g_test.assertEquals(3, v8f(a)); +}; + +g_suite.testV8CanSetBrowserArrayElements = function() { + var a = [1, 2, 3]; + var v8f = window.g_plugin.eval('function(x) { x[1] = 7; }'); + v8f(a); + g_test.assertEquals(7, a[1]); +}; + +g_suite.testV8CanSetBrowserArrayLength = function() { + var a = [1, 2, 3]; + var v8f = window.g_plugin.eval('function(x) { x.length = 10; }'); + v8f(a); + g_test.assertEquals(10, a.length); +}; + +g_suite.testV8CanIterateOverBrowserArray = function() { + var a = [1, 2, 3]; + var v8f = window.g_plugin.eval( + 'function(x) { var total = 0; for (var i in x) { total += x[i]; } return total; }'); + g_test.assertEquals(6, v8f(a)); +}; + +g_suite.testIsArrayWorksInV8ForBrowserArrays = function() { + var v8f = g_plugin.eval('function(x) { return o3djs.base.isArray(x); }'); + g_test.assertTrue(v8f([1, 2, 3])); +}; + +g_suite.testIsArrayWorksInV8ForV8Arrays = function() { + g_test.assertFalse(g_plugin.eval('o3djs.base.isArray(undefined)')); + g_test.assertFalse(g_plugin.eval('o3djs.base.isArray(7)')); + g_test.assertTrue(g_plugin.eval('o3djs.base.isArray([1, 2, 3])')); +}; + +g_suite.testV8CanQueryBrowserProperties = function() { + var a = { p : 123 }; a[1] = 321; + var v8f = window.g_plugin.eval( + 'function(x) { var all = ""; for (m in x) { all += m; } return all; }'); + + // The EcmaScript spec says the order property names are returned is + // implementation dependent. + g_test.assertTrue('1p' === v8f(a) || 'p1' === v8f(a)); +}; + +g_suite.testV8CanRemoveBrowserProperties = function() { + if (!isSafari) { + var a = { p : 123 }; + var v8f = window.g_plugin.eval('function(x) { return delete x.p; }'); + g_test.assertTrue(v8f(a)); + // check property does not exist + g_test.assertEquals('undefined', typeof(a.p)); + // delete should still succeed if the property does not exist + g_test.assertTrue(v8f(a)); + } +}; + +g_suite.testV8DeleteOperatorReturnsFalseIfPropertyCannotBeRemoved = function() { + g_test.assertFalse(window.g_plugin.eval('delete plugin.client')); +}; + +g_suite.testV8CanInvokeBrowserMethods = function() { + function C() { this.f = 7; this.m = function() { return this.f; } } + c = new C(); + var v8f = window.g_plugin.eval('function(x) { return x.m(); }'); + g_test.assertEquals(7, v8f(c)); +}; + +g_suite.testV8CodeReceivesAnExceptionIfBrowserMethodCallFails = function() { + var v8f = window.g_plugin.eval( + 'function() { try { plugin.nonExistentFunction(); } catch(e) { return e; } }'); + g_test.assertEquals( + "TypeError: Object [object Object] has no method 'nonExistentFunction'", + v8f().toString()); +}; + +// This won't work until will can support intercepting on V8 objects built +// from FunctionTemplates. +//g_suite.testV8CanInvokeBrowserFunctionsWithExplicitThisThroughCallAndApply = +// function() { +// var this_copy, arg_copy; +// function f(arg) { this_copy = this; arg_copy = arg; return arg; } +// var v8f = window.g_plugin.eval('function(x) { return x(7); }'); +// var obj = {}; +// g_test.assertEquals(7, v8f.call(obj, 7)); +// g_test.assertEquals(obj, this_copy); +// g_test.assertEquals(7, arg_copy); +// obj = {}; +// g_test.assertEquals(8, v8f.apply(obj, [7])); +// g_test.assertEquals(obj, this_copy); +// g_test.assertEquals(8, arg_copy); +//} + +g_suite.testStringValueOfBrowserObjectInV8IsDefault = function() { + var v8f = window.g_plugin.eval('function(x) { return x.toString(); }'); + g_test.assertEquals('[object Object]', v8f({})); +}; + +g_suite.testStringValueOfBrowserObjectInV8CanBeOverriden = function() { + var v8f = window.g_plugin.eval('function(x) { return x.toString(); }'); + g_test.assertEquals('foo', v8f({ toString: function() { return 'foo' } })); +}; + +g_suite.testV8CanInvokeNativeMethod = function() { + g_test.assertEquals('My pack', window.g_plugin.eval( + 'var pack = plugin.client.createPack(); pack.name = \"My pack\"; pack.name')); +}; + +g_suite.testV8CanInvokeNativeObject = function() { + g_test.assertArrayEquals([-1, -1, -2], window.g_plugin.eval( + 'var b = plugin.o3d.BoundingBox(' + + '[-1, -1, -2], [1, 2, 4]); b.minExtent')); +}; + +g_suite.testV8ExceptionsInPluginEvalResultInErrorCallback = function() { + var error = 'no error'; + var exceptionThrown = false; + window.g_plugin.client.setErrorCallback(function(e) { + error = e; }); + try { + window.g_plugin.eval('throw "error";'); + } catch(e) { + exceptionThrown = true; + } + // Chrome bug: http://code.google.com/p/chromium/issues/detail?id=5748 + if (!isChrome && !isSafari) { + g_test.assertTrue(exceptionThrown); + } + g_test.assertEquals('Uncaught error in throw "error";', error); +}; + +g_suite.testV8ExceptionsInFunctionCallResultInErrorCallback = function() { + var v8f = window.g_plugin.eval('function() { throw "error"; }'); + var error = 'no error'; + var exceptionThrown = false; + window.g_plugin.client.setErrorCallback(function(e) { + error = e; }); + try { + v8f(); + } catch(e) { + exceptionThrown = true; + } + // Chrome bug: http://code.google.com/p/chromium/issues/detail?id=5748 + if (!isChrome && !isSafari) { + g_test.assertTrue(exceptionThrown); + } + g_test.assertEquals('Uncaught error in function() { throw "error"; }', error); +}; + +g_suite.testV8ExceptionsInMethodCallResultInErrorCallback = function() { + var obj = window.g_plugin.eval('({ f: function() { throw "error"; } })'); + var error = 'no error'; + var exceptionThrown = false; + window.g_plugin.client.setErrorCallback(function(e) { + error = e; }); + try { + obj.f(); + } catch(e) { + exceptionThrown = true; + } + // Chrome bug: http://code.google.com/p/chromium/issues/detail?id=5748 + if (!isChrome && !isSafari) { + g_test.assertTrue(exceptionThrown); + } + g_test.assertEquals( + 'Uncaught error in ({ f: function() { throw "error"; } })', + error); +}; + +g_suite.testV8ExceptionsInConstructorCallResultInErrorCallback = function() { + // Chrome bug: http://code.google.com/p/chromium/issues/detail?id=3285 + if (!isChrome && !isSafari && !isFirefox2) { + var obj = window.g_plugin.eval('function() { throw "error"; }'); + var error = 'no error'; + var exceptionThrown = false; + window.g_plugin.client.setErrorCallback(function(e) { + error = e; }); + try { + new obj(); + } catch(e) { + exceptionThrown = true; + } + // Chrome bug: http://code.google.com/p/chromium/issues/detail?id=5748 + if (!isChrome && !isSafari) { + g_test.assertTrue(exceptionThrown); + } + g_test.assertEquals( + 'Uncaught error in function() { throw "error"; }', error); + } +}; + +g_suite.testV8CanAccessBrowserGlobals = function() { + window.g_global = 7; + g_test.assertEquals(7, window.g_plugin.eval('g_global')); +}; + +g_suite.testV8ModificationsToBrowserGlobalsAreOnlyLocallyVisible = function() { + window.g_global = 7; + g_test.assertEquals(8, window.g_plugin.eval('g_global = 8; g_global')); + g_test.assertEquals(7, window.g_global); +}; + +g_suite.testV8CanAccessPluginThroughPluginGlobal = function() { + // http://code.google.com/p/chromium/issues/detail?id=5751 + if (!isChrome && !isSafari) { + g_test.assertEquals(g_plugin.client, window.g_plugin.eval('plugin.client')); + } +}; + +g_suite.testEvalFailsWithBadArguments = function() { + // Chrome bug: http://code.google.com/p/chromium/issues/detail?id=5748 + if (!isChrome && !isSafari) { + var numExceptions = 0; + try { + window.g_plugin.eval(); + } catch (e) { + ++numExceptions; + } + try { + window.g_plugin.eval('a', 'b'); + } catch (e) { + ++numExceptions; + } + try { + window.g_plugin.eval(7); + } catch (e) { + ++numExceptions; + } + g_test.assertEquals(3, numExceptions); + } +}; + +g_suite.testExceptionThrownIfV8CodeIsInvalid = function() { + var error = 'no error'; + var exceptionThrown = false; + window.g_plugin.client.setErrorCallback(function(e) { + error = e; }); + try { + window.g_plugin.eval('+1)'); + } catch (e) { + exceptionThrown = true; + } + g_test.assertEquals('Uncaught SyntaxError: Unexpected token ) in +1)', error); + if (!isSafari && !isChrome) { + g_test.assertTrue(exceptionThrown); + } +}; + +g_suite.testV8CanAccessDOM = function() { + if (!isInternetExplorer) { + g_test.assertEquals('P', window.g_plugin.eval( + "document.createElement('P').tagName")); + } +}; + +g_suite.testV8CanRunUtilityCodeNatively = function() { + var result = g_plugin.eval("o3djs.math.addVector([1, 2, 3], [3, 2, 1])"); + g_test.assertArrayEquals([4, 4, 4], result); +}; + +o3djs.provide('myNamespace'); + +myNamespace.anUndefinedConstant = undefined; + +myNamespace.aNumberConstant = 7; + +myNamespace.aBooleanConstant = true; + +myNamespace.anEscapedStringConstant = 'foo\r\n\tbar'; + +myNamespace.anUnescapedStringConstant = 'foo bar'; + +myNamespace.aNullConstant = null; + +myNamespace.anObjectConstant = {a: 'foo'}; + +myNamespace.anArrayConstant = [1, 2, 3]; + +myNamespace.doSomething = function() { + return 7; +}; + +myNamespace.AConstructor = function(a) { + this.a = a; +}; + +myNamespace.AConstructor.prototype.getA = function() { + return this.a; +}; + +myNamespace.getPlugin = function() { + return plugin; +}; + +myNamespace.doSomethingInBrowser = function() { + o3djs.BROWSER_ONLY; + myNamespace.didSomethingInBrowser = true; + return 7; +}; + +myNamespace.aRegExp = /Foo\n\r/gim; + +g_suite.testProvidedCodeRunsInV8 = function() { + g_test.assertTrue('client' in g_plugin.eval('myNamespace.getPlugin()')); +}; + +g_suite.testV8CanAccessUndefinedInAProvidedNamespace = function() { + myNamespace.anUndefinedConstant = 7; + g_test.assertEquals(undefined, g_plugin.eval( + 'myNamespace.anUndefinedConstant')); +}; + +g_suite.testV8CanAccessNumbersInAProvidedNamespace = function() { + myNamespace.aNumberConstant = undefined; + g_test.assertEquals(7, g_plugin.eval('myNamespace.aNumberConstant')); +}; + +g_suite.testV8CanAccessBooleansInAProvidedNamespace = function() { + myNamespace.aBooleanConstant = undefined; + g_test.assertTrue(g_plugin.eval('myNamespace.aBooleanConstant')); +}; + +g_suite.testV8CanAccessEscapedStringsInAProvidedNamespace = function() { + myNamespace.anEscapedStringConstant = undefined; + g_test.assertEquals('foo\r\n\tbar', g_plugin.eval( + 'myNamespace.anEscapedStringConstant')); +}; + +g_suite.testV8CanAccessUneapedStringsInAProvidedNamespace = function() { + myNamespace.anUnescapedStringConstant = undefined; + g_test.assertEquals('foo bar', g_plugin.eval( + 'myNamespace.anUnescapedStringConstant')); +}; + +g_suite.testV8CanAccessNullInAProvidedNamespace = function() { + myNamespace.aNullConstant = undefined; + g_test.assertEquals(null, g_plugin.eval('myNamespace.aNullConstant')); +}; + +g_suite.testV8CanAccessObjectsInAProvidedNamespace = function() { + myNamespace.anObjectConstant = undefined; + g_test.assertEquals('foo', g_plugin.eval('myNamespace.anObjectConstant.a')); +}; + +g_suite.testV8CanAccessArraysInAProvidedNamespace = function() { + myNamespace.anArrayConstant = undefined; + g_test.assertArrayEquals([1, 2, 3], g_plugin.eval( + 'myNamespace.anArrayConstant')); +}; + +g_suite.testV8CanInvokeFunctionsInAProvidedNamespace = function() { + myNamespace.doSomething = undefined; + g_test.assertEquals(7, g_plugin.eval('myNamespace.doSomething()')); +}; + +g_suite.testV8CanInvokeConstructorsAndPrototypeMethodsInAProvidedNamespace = + function() { + myNamespace.AConstructor = undefined; + g_test.assertEquals(7, g_plugin.eval( + 'new myNamespace.AConstructor(7).getA()')); +}; + +g_suite.testV8CanInvokeFunctionsAnnotatedAsRunningInTheBrowser = function() { + g_test.assertEquals(7, g_plugin.eval('myNamespace.doSomethingInBrowser()')); + g_test.assertTrue(myNamespace.didSomethingInBrowser); +}; + +g_suite.textV8CanAccessRegExpInAProvidedNamespace = function() { + myNamespace.aRegExp = undefined; + g_test.assertEquals('Foo\n\r', g_plugin.eval('myNamespace.aRegExp.source')); + g_test.assertTrue(g_plugin.eval('myNamespace.aRegExp.global')); + g_test.assertTrue(g_plugin.eval('myNamespace.aRegExp.multiline')); + g_test.assertTrue(g_plugin.eval('myNamespace.aRegExp.ignoreCase')); +} + +g_suite.testV8CanAccessBrowserO3djs = function() { + g_test.assertEquals(o3djs, g_plugin.eval('o3djs.browser')); +}; + +g_suite.testV8CanAccessGlobalsThroughO3djs = function() { + g_test.assertEquals(navigator.userAgent, + g_plugin.eval('o3djs.global.navigator.userAgent')); +}; + +g_suite.testV8CanAccessO3dNamespaceThroughO3djs = function() { + g_test.assertTrue(g_plugin.eval('g_plugin.o3d === o3djs.base.o3d')); +}; + +function initStep2(clientElements) { + g_test = o3djs.test; + g_plugin = clientElements[0]; + g_testResult = g_test.runTests(g_suite); +}; + +window.onload = function() { + o3djs.util.makeClients(initStep2); +}; + +</script> +</body> +</html> diff --git a/o3d/tests/selenium/tests/version-check-test.html b/o3d/tests/selenium/tests/version-check-test.html new file mode 100644 index 0000000..b16d878 --- /dev/null +++ b/o3d/tests/selenium/tests/version-check-test.html @@ -0,0 +1,90 @@ +<!-- +Copyright 2009, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + +<!-- +Test we can check for the version. +--> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title> +Version Check +</title> +<!-- Include sample javascript library functions--> +<script + type="text/javascript" + src="../../../samples/o3djs/base.js"></script> + +<!-- Our javascript code --> +<script type="text/javascript"> +o3djs.require('o3djs.util'); + +// Events +// init() once the page has finished loading. +window.onload = init; + +// global variables +var g_testResult; + +/** + * Request version 999999 which should always fail. + */ +function init() { + o3djs.util.makeClients(haveVersion, '', '999999', dontHaveVersion); +} + +function dontHaveVersion() { + document.getElementById('result').innerHTML = + 'success: version 999999 not available'; + g_testResult = true; +} + +/** + * + */ +function haveVersion() { + document.getElementById('result').innerHTML = + 'failure: version 999999 is supposedly available!'; + g_testResult = false; +} +</script> +</head> +<body> +<h1>Version Check</h1> +Check that asking for a non-existent version fails<br/> +<!-- Start of O3D plugin --> +<div id="o3d" style="width: 200px; height: 200px;"></div> +<!-- End of O3D plugin --> +<div>Result: <span id="result"></span><div> +</body> +</html> diff --git a/o3d/tests/selenium/tests/window-overlap-test.html b/o3d/tests/selenium/tests/window-overlap-test.html new file mode 100644 index 0000000..8ce4e16 --- /dev/null +++ b/o3d/tests/selenium/tests/window-overlap-test.html @@ -0,0 +1,119 @@ +<!-- +Copyright 2009, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + +<!-- +Window Overlap Test + +Make sure client areas that are not visible because of overlapping windows do +not render. +--> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title> +Window Overlap Test +</title> +<!-- Include sample javascript library functions--> +<script type="text/javascript" src="../../../samples/o3djs/base.js"></script> + +<!-- Our javascript code --> +<script type="text/javascript"> +o3djs.require('o3djs.util'); +o3djs.require('o3djs.rendergraph'); + +// Events +// init() once the page has finished loading. +// unload() when the page is unloaded. +window.onload = init; +window.onunload = uninit; + +// global variables +var g_client; +var g_pack; +var g_viewInfo; +var g_renderCount = 0; +var g_finished = false; + +function onRender() { + g_viewInfo.clearBuffer.clearColor = [Math.random(), + Math.random(), + Math.random(), + 1]; + g_renderCount += 1; +} + +/** + * Creates the client areas. + */ +function init() { + o3djs.util.makeClients(initStep2); +} + +/** + * Initializes O3D and loads the model into the transform graph. + * @param {Array} clientElements Array of o3d object elements. + */ +function initStep2(clientElements) { + var o3dElement = clientElements[0]; + + g_client = o3dElement.client; + g_pack = g_client.createPack(); + + g_viewInfo = o3djs.rendergraph.createBasicView( + g_pack, + g_client.root, + g_client.renderGraphRoot); + + g_client.setRenderCallback(onRender); + + g_finished = true; +} + +/** + * Cleans up. + */ +function uninit() { + g_client.clearRenderCallback(); +} +</script> +</head> +<body> +<h1>Window Overlap Test</h1> +This test verifies that client areas that are not visible because of overlapping +windows do not render. +<br/> +<!-- Start of O3D plugin --> +<div id="o3d" style="width: 100px; height: 100px;"></div> +<!-- End of O3D plugin --> +</body> +</html> diff --git a/o3d/tests/selenium/tests/window-overlap-top.html b/o3d/tests/selenium/tests/window-overlap-top.html new file mode 100644 index 0000000..250addc --- /dev/null +++ b/o3d/tests/selenium/tests/window-overlap-top.html @@ -0,0 +1,63 @@ +<!-- +Copyright 2009, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + +<!-- +Window Overlap Test Top + +See window-overlap-test.html +--> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title> +Window Overlap Test Top Window +</title> +<script type="text/javascript"> +// Events +// init() once the page has finished loading. +window.onload = init; + +var g_finished = false; + +function init() { + g_finished = true; +} +</script> +</head> +<body> +<h1>Window Overlap Test Top Window</h1> +This test verifies that client areas that are not visible because of overlapping +windows do not render. +<br/> +</body> +</html> diff --git a/o3d/tests/test_driver.bat b/o3d/tests/test_driver.bat new file mode 100644 index 0000000..c9e0e4a --- /dev/null +++ b/o3d/tests/test_driver.bat @@ -0,0 +1,33 @@ +@echo off +REM Copyright 2009, Google Inc. +REM All rights reserved. +REM +REM Redistribution and use in source and binary forms, with or without +REM modification, are permitted provided that the following conditions are +REM met: +REM +REM * Redistributions of source code must retain the above copyright +REM notice, this list of conditions and the following disclaimer. +REM * Redistributions in binary form must reproduce the above +REM copyright notice, this list of conditions and the following disclaimer +REM in the documentation and/or other materials provided with the +REM distribution. +REM * Neither the name of Google Inc. nor the names of its +REM contributors may be used to endorse or promote products derived from +REM this software without specific prior written permission. +REM +REM THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +REM "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +REM LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +REM A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +REM OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +REM SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +REM LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +REM DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +REM THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +REM (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +REM OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +set PYTHONDIR=%~dp0..\..\..\..\third_party\python_24 +call %PYTHONDIR%\setup_env.bat +%PYTHONDIR%\python.exe %~dp0\test_driver.py %* diff --git a/o3d/tests/test_driver.py b/o3d/tests/test_driver.py new file mode 100644 index 0000000..891ecec --- /dev/null +++ b/o3d/tests/test_driver.py @@ -0,0 +1,433 @@ +#!/usr/bin/python2.4 +# Copyright 2009, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +"""Test harness script that invokes O3D system-tests. + +This script constructs the necessary testing environment required for the +DirectX-based O3D system-tests. It invokes each test within the PIX +debugging tool to capture the graphics command stream and framebuffer +contents. + +See (http://wiki.corp.google.com/twiki/bin/view/Main/ClientThreeDTestingPlan) +for the o3d testing plan. + +Usage: + test_driver.py [-capture_only] [-hardware] + +The script will scan all of the directories, and invoke system-tests for all +<name>_test directories present. Each of the system-tests in system_tests.exe +will be invoked one at a time through PIXWin.exe. PIX has been configured +to interact with the testing framework to capture graphics command streams +and framebuffer contents. + +After the test has executed, the script will parse the persisted log files +and compare the generated results. + +The framework assumes that each test-case is named with a camel-caps +translation of the directory name. So in the case of the directory +tests\import_test, the system invokes the gUnit test ImportTest. + +Command Arguments: + -capture_only: The script will only capture results. All verification with + reference-data will be bypassed. This flag should be used when updating the + reference-data. + + - hardware: The the system tests will execute using the graphics hardware, as + opposed to the software reference rasterizer. Use this mode to look for + problems related to a specific hardware platform. +""" + + +import os +import re +from stat import ST_MODE +from stat import S_ISDIR +import sys + +_PIX_EXECUTABLE = '.\PIXWin.exe' + +# Template for the command line required to invoke a system-test within PIX. +_PIX_EXPERIMENT_INVOKE = ('%s %s -start -runfile %s -targetstartfolder %s ' + '-targetargs %s') + +# Template for the command line required to invoke PIX when constructing a +# .csv file from a .PIXRun file. +_PIX_RUNFILE_INVOKE = '%s %s -exporttocsv %s' + +# Template command line argument for the gunit system that selectively +# executes individual groups of tests. +_GUNIT_INVOKE = '--gunit_filter=%s.*' +_SYSTEM_TEST = '.\system_test.exe' +_EXPERIMENT_FILE_REFERENCE = 'testing_framework_reference.PIXExp' +_EXPERIMENT_FILE_HARDWARE = 'testing_framework_hardware.PIXExp' + +# Command line required to invoke the perceptual diff utility. +_PDIFF = ('perceptualdiff.exe %s %s -verbose -fov 45 -threshold 40000') + +# Regular expression used to search for hexadecimal pointer values in +# generated log files +_HEX_EXPRESSION = re.compile('0x[0-9ABCDEF]+') + +# Constant command argument string to enable capture-only mode. +_CAPTURE_FLAG = '-capture_only' + +# Command flags to specify usage of the hardware rasterizer for the tests. +_HARDWARE_RASTERIZER = '-hardware' + +# Boolen set to True if test results should be captured and not validated. +_GENERATE_ONLY = False + +# Boolean set to True if hardware rasterizer is to be used instead of the DX +# reference rasterizer. +_HARDWARE_DEVICE = False + + +def ConstructTestName(filesystem_name): + """Returns a camel-caps translation of the input string. + + Args: + filesystem_name: The name of the test, as found on the file-system. + Typically this name is_of_this_form. + + Returns: + A camel-caps version of the input string. _ delimiters are removed, and + the first letters of words are capitalized. + """ + names = filesystem_name.split('_') + test_name = '' + for word in names: + test_name += word.upper()[0] + word[1:] + return test_name + + +def AssertCapturedFrames(test_name): + """Performs the image validation for test-case frame captures. + + Args: + test_name: The name of the test, as found on the file-system. + + Returns: + True if all images match within tolerance, false otherwise. + """ + print 'Status: Validating captured frames against reference data.' + + reference_files = os.listdir('./' + test_name + '/reference_frames') + generated_files = os.listdir('./' + test_name) + generated_files = [(file_name) for file_name in generated_files + if '.png' in file_name] + + if set(reference_files) != set(generated_files): + print 'Error: Reference file set does not match generated file set.' + print 'Reference files: ' + ', '.join(reference_files) + print 'Generated files: ' + ', '.join(generated_files) + return False + + # Assuming both the result and reference image sets are the same size, + # verify that corresponding images are similar within tolerance. + for file in reference_files: + reference_file = test_name + '/reference_frames/' + file + generated_file = test_name + '/' + file + if os.system(_PDIFF % (reference_file, generated_file)): + error = ('Error: Reference framebuffer (%s) does not match generated ' + 'file (%s).') + print error % (reference_file, generated_file) + return False + + return True + + +def GenerateCSVStream(test_name): + """Invokes PIX to convert a PIXRun file to a .csv file. + + Args: + test_name: The name of the test for which the .csv file is + to be generated. + """ + + runfile_invoke = _PIX_RUNFILE_INVOKE % ( + _PIX_EXECUTABLE, + test_name + '/' + test_name + '.PIXRun', + test_name + '/' + test_name + '.csv') + + os.system(runfile_invoke) + + +def RemovePointerReferences(call_log): + """Returns the input argument with all pointer values removed. + + Args: + call_log: String containing an dx call-log entry. + + Returns: + The input string with all substrings matching '0x[0-9A-F]+', which is the + pointer syntax used for the log files, removed. + """ + + return _HEX_EXPRESSION.sub('', call_log) + + +def PartitionCSVLine(line): + """Returns a list of all column values in a comma-separated-value line. + + Args: + line: The input line from a comma-separated-value source. + + Returns: + CSV files may include quoted text segments containing commas. This + routine will return an array of all of the columns present in the line, + respecting quoted regions. + """ + + # This routine is more complicated than expected due to the presence of + # quoted lists within colums. The algorithm proceeds by first splitting + # the line by quoted sub-strings. Sub-strings not matching a quoted + # expression are then split on ','. + quoted_column = re.compile('(\"[^\"]*\")') + block_partitions = quoted_column.split(line) + + output_columns = [] + + for chunk in block_partitions: + # If this chunk is a quoted string, append it to the output verbatim. + if quoted_column.match(chunk): + output_columns += [chunk] + else: + output_columns += chunk.split(',') + + # Return the output set of columns with all empty entries removed. + # Empty columns will be present due to the interaction of the split by + # quoted string, and split by ','. + # For example: here, is, "a (tuple, example)", to, try + # After the first split: ['here, is, ', 'a (tuple, example)', 'to, try'] + # After the second split: + # ['here', 'is', '', 'a (tuple, example)', 'to', 'try'] + # Since these empty columns are not present in the original list, we remove + # them here. + return [(column) for column in output_columns if column != ""] + + +def AssertCapturedStreams(test_name): + """Performes graphics command stream verification for test with name + test_name. + + Args: + test_name: The name of the test, as found on the file-system. + + Returns: + Returns true if the generated testing streams match the reference streams. + """ + + print 'Status: Validating generated command streams.' + + generated_stream = open(test_name + '/' + test_name + '.csv') + reference_stream = open(test_name + '/reference_stream.csv') + + reference_lines = reference_stream.readlines() + generated_lines = generated_stream.readlines() + + if len(reference_lines) != len(generated_lines): + print 'Error: Reference and generated logs differ in length.' + return False + + # Compare each of the log lines from both files. + for index in range(0, len(reference_lines)): + generated_line = generated_lines[index] + reference_line = reference_lines[index] + + # Partition each csv line correctly wrt quoted blocks + reference_columns = PartitionCSVLine(reference_line) + generated_columns = PartitionCSVLine(generated_line) + + # Only perform deep-validation on 'Call' commands. + if reference_columns[0] != 'Call': + continue + + generated_log = RemovePointerReferences(generated_columns[2]) + reference_log = RemovePointerReferences(reference_columns[2]) + + if (generated_log != reference_log or + reference_columns[0] != generated_columns[0] or + reference_columns[1] != generated_columns[1]): + print 'Error: Log file mis-match. Line: %i' % index + print 'Reference = %s' % reference_line + print 'Generated = %s' % generated_line + return False + + return True + + +def InvokeTest(test_name): + """Invoke the system-test with name test_name. + + Args: + test_name: The name of the test, as found on the file-system. + + Returns: + True if the test succeeds, false otherwise. + """ + + global _GENERATE_ONLY + + if _HARDWARE_DEVICE: + pix_experiment_file = _EXPERIMENT_FILE_HARDWARE + else: + pix_experiment_file = _EXPERIMENT_FILE_REFERENCE + + print 'Status: Executing test : %s\n' % test_name + gunit_invoke = _GUNIT_INVOKE % ConstructTestName(test_name) + pix_invoke = _PIX_EXPERIMENT_INVOKE % (_PIX_EXECUTABLE, + pix_experiment_file, + test_name + '.PIXRun', + test_name, + gunit_invoke) + os.system(pix_invoke) + + # Invoke PIX to translate the just created .PIXRun file to a .csv suitable + # for parsing. + GenerateCSVStream(test_name) + + # If invoked for capture-only, then exit here before validation. + if _GENERATE_ONLY: + return True + + if not(AssertCapturedFrames(test_name)): + return False + + if not(AssertCapturedStreams(test_name)): + return False + + return True + + +def BuildTestList(): + """Returns a list of all available system tests. + + Returns: + A list of test_names, constructed from the set of directory names + in the current directory. All directories containing the substring + 'test' are included in the returned set. + """ + + testing_directory = os.listdir('.') + test_list = [] + + for test in testing_directory: + mode = os.stat(test)[ST_MODE] + if ('test' in test and test != 'unittest_data' and + test != 'bitmap_test' and + test != 'conditioner_test_data' and S_ISDIR(mode)): + test_list += [test] + return test_list + + +def ValidateArgs(argv): + """Validates the script arguments, and displays a help message, + if necessary. + + Args: + argv: Array of script arguments, in argv format. + + Returns: + True if the arguments are valid. See the usage description for + valid arguments. + """ + + global _GENERATE_ONLY + global _HARDWARE_DEVICE + + # TODO : Make use of the gflags library to ease parsing of command line + # arguments. + argument_set = [_CAPTURE_FLAG, _HARDWARE_RASTERIZER] + + for arg in argv[1:]: + if arg not in argument_set: + print 'O3D System-Test Harness - Usage:' + print ('test_driver.py [' + _CAPTURE_FLAG + '] [' + + _HARDWARE_RASTERIZER + ']') + print 'Arguments:' + print _CAPTURE_FLAG + ' : Force generation of reference data.' + print (_HARDWARE_RASTERIZER + + ' : Force usage of hardware for test data generation') + return False + + if _CAPTURE_FLAG in argv[1:]: + _GENERATE_ONLY = True + + if _HARDWARE_RASTERIZER in argv[1:]: + print 'Rendering with local graphics hardware.' + _HARDWARE_DEVICE = True + else: + print 'Rendering with DX9 reference rasterizer.' + + return True + + +def main(argv): + """Main entry point of the script. + + Args: + argv: The c-like arguments to the script. + + Returns: + True if all tests pass, false othwerwise. + """ + + print 'Running O3D system tests.' + + if not ValidateArgs(argv): + return False + + os.chdir(os.path.dirname(argv[0])) + + test_set = BuildTestList() + + # Invoke each test, tracking failures. + test_failures = [] + for test in test_set: + if not InvokeTest(test): + test_failures += [test] + + if len(test_failures) == 0: + print 'Success: All tests passed.' + return True + else: + print 'Error Summary: The following tests failed:' + print test_failures + return False + + +if __name__ == '__main__': + if main(sys.argv): + # Return with a 0 for success (per unix convention). + sys.exit(0) + else: + # Return with a 1 for failure (per unix convention). + sys.exit(1) diff --git a/o3d/tests/testing_framework_hardware.PIXExp b/o3d/tests/testing_framework_hardware.PIXExp new file mode 100644 index 0000000..0495ae03 --- /dev/null +++ b/o3d/tests/testing_framework_hardware.PIXExp @@ -0,0 +1,2 @@ +<?xml version="1.0"?> +<PIXExperiment><Version><ExpFileVersion>202</ExpFileVersion></Version><TargetApp><TargetPath>system_tests.exe</TargetPath><StartFolder></StartFolder><Args></Args><SkipProcesses>0</SkipProcesses><RecordDiagnosticLog>0</RecordDiagnosticLog><IncludeDebugSpew>0</IncludeDebugSpew><DisableD3DXAnalysis>0</DisableD3DXAnalysis></TargetApp><Columns><Column><Name>EDID</Name><ColumnID>1</ColumnID><Flags>0</Flags><Type>3</Type><Format>%d</Format></Column><Column><Name>Event Type</Name><ColumnID>2</ColumnID><Flags>0</Flags><Type>3</Type><Format>%d</Format></Column><Column><Name>EID</Name><ColumnID>3</ColumnID><Flags>0</Flags><Type>3</Type><Format>%d</Format></Column><Column><Name>Parent EID</Name><ColumnID>4</ColumnID><Flags>0</Flags><Type>3</Type><Format>%d</Format></Column><Column><Name>Children</Name><ColumnID>11</ColumnID><Flags>0</Flags><Type>6</Type><Format>%d</Format></Column><Column><Name>Parent</Name><ColumnID>10</ColumnID><Flags>0</Flags><Type>2</Type><Format>%d</Format></Column><Column><Name>Flags</Name><ColumnID>5</ColumnID><Flags>0</Flags><Type>2</Type><Format>0x%08X</Format></Column><Column><Name>Event</Name><ColumnID>6</ColumnID><Flags>0</Flags><Type>4</Type><Format>%s</Format></Column><Column><Name>StartTime</Name><ColumnID>7</ColumnID><Flags>0</Flags><Type>5</Type><Format>%I64i</Format></Column><Column><Name>Path</Name><ColumnID>13</ColumnID><Flags>0</Flags><Type>1</Type><Format>%s</Format></Column><Column><Name>Path2</Name><ColumnID>14</ColumnID><Flags>0</Flags><Type>1</Type><Format>%s</Format></Column><Column><Name>Version</Name><ColumnID>15</ColumnID><Flags>0</Flags><Type>1</Type><Format>%s</Format></Column><Column><Name>TimeLastModified</Name><ColumnID>16</ColumnID><Flags>0</Flags><Type>1</Type><Format>%s</Format></Column><Column><Name>ProcessID</Name><ColumnID>23</ColumnID><Flags>0</Flags><Type>3</Type><Format>%d</Format></Column><Column><Name>SessionStartTimeStamp</Name><ColumnID>24</ColumnID><Flags>0</Flags><Type>5</Type><Format>%I64i</Format></Column><Column><Name>Frame</Name><ColumnID>9</ColumnID><Flags>0</Flags><Type>3</Type><Format>%d</Format></Column><Column><Name>Duration</Name><ColumnID>8</ColumnID><Flags>0</Flags><Type>5</Type><Format>%I64i</Format></Column><Column><Name>FPS</Name><ColumnID>12</ColumnID><Flags>0</Flags><Type>0</Type><Format>%0.01f</Format></Column><Column><Name>ThisEventPos</Name><ColumnID>21</ColumnID><Flags>0</Flags><Type>5</Type><Format>%I64i</Format></Column><Column><Name>NextSiblingPos</Name><ColumnID>22</ColumnID><Flags>0</Flags><Type>5</Type><Format>%I64i</Format></Column><Column><Name>User Event Name</Name><ColumnID>17</ColumnID><Flags>0</Flags><Type>1</Type><Format>%s</Format></Column><Column><Name>PackedCallPackage</Name><ColumnID>19</ColumnID><Flags>0</Flags><Type>7</Type><Format></Format></Column><Column><Name>Object Pointer</Name><ColumnID>20</ColumnID><Flags>0</Flags><Type>2</Type><Format>0x%08X</Format></Column></Columns><EventDescs><EventDesc><Name>Session Start</Name><EventType>1</EventType><EDID>1</EDID><EventDescColumns><EventDescColumn><ColumnID>1</ColumnID><String>(edid)</String></EventDescColumn><EventDescColumn><ColumnID>2</ColumnID><String>CalcOnLoad,Const,1</String></EventDescColumn><EventDescColumn><ColumnID>3</ColumnID><String>(eid)</String></EventDescColumn><EventDescColumn><ColumnID>4</ColumnID><String>CalcOnLoad,Const,-1</String></EventDescColumn><EventDescColumn><ColumnID>5</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>7</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>8</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>6</ColumnID><String>CalcOnLoad,FormatText,0,Start Session</String></EventDescColumn><EventDescColumn><ColumnID>13</ColumnID><String>(expfilepath)</String></EventDescColumn><EventDescColumn><ColumnID>14</ColumnID><String>(runfilepath)</String></EventDescColumn><EventDescColumn><ColumnID>24</ColumnID><String>(sessionstarttimestamp)</String></EventDescColumn></EventDescColumns></EventDesc><EventDesc><Name>Session End</Name><EventType>2</EventType><EDID>2</EDID><EventDescColumns><EventDescColumn><ColumnID>1</ColumnID><String>(edid)</String></EventDescColumn><EventDescColumn><ColumnID>2</ColumnID><String>CalcOnLoad,Const,2</String></EventDescColumn><EventDescColumn><ColumnID>3</ColumnID><String>(eid)</String></EventDescColumn><EventDescColumn><ColumnID>4</ColumnID><String>CalcOnLoad,Const,-1</String></EventDescColumn><EventDescColumn><ColumnID>5</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>7</ColumnID><String>(time)</String></EventDescColumn><EventDescColumn><ColumnID>8</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>6</ColumnID><String>CalcOnLoad,FormatText,0,End Session</String></EventDescColumn></EventDescColumns></EventDesc><EventDesc><Name>Process Start</Name><EventType>3</EventType><EDID>3</EDID><EventDescColumns><EventDescColumn><ColumnID>1</ColumnID><String>(edid)</String></EventDescColumn><EventDescColumn><ColumnID>2</ColumnID><String>CalcOnLoad,Const,3</String></EventDescColumn><EventDescColumn><ColumnID>3</ColumnID><String>(eid)</String></EventDescColumn><EventDescColumn><ColumnID>4</ColumnID><String>CalcOnLoad,Const,-1</String></EventDescColumn><EventDescColumn><ColumnID>5</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>7</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>8</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>6</ColumnID><String>CalcOnLoad,FormatText,0,Start Process</String></EventDescColumn><EventDescColumn><ColumnID>13</ColumnID><String>(processpath)</String></EventDescColumn><EventDescColumn><ColumnID>15</ColumnID><String>(processversion)</String></EventDescColumn><EventDescColumn><ColumnID>16</ColumnID><String>(processtimelastmodified)</String></EventDescColumn><EventDescColumn><ColumnID>23</ColumnID><String>(processid)</String></EventDescColumn></EventDescColumns></EventDesc><EventDesc><Name>Process End</Name><EventType>4</EventType><EDID>4</EDID><EventDescColumns><EventDescColumn><ColumnID>1</ColumnID><String>(edid)</String></EventDescColumn><EventDescColumn><ColumnID>2</ColumnID><String>CalcOnLoad,Const,4</String></EventDescColumn><EventDescColumn><ColumnID>3</ColumnID><String>(eid)</String></EventDescColumn><EventDescColumn><ColumnID>4</ColumnID><String>CalcOnLoad,Const,-1</String></EventDescColumn><EventDescColumn><ColumnID>5</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>7</ColumnID><String>(time)</String></EventDescColumn><EventDescColumn><ColumnID>8</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>6</ColumnID><String>CalcOnLoad,FormatText,0,End Process</String></EventDescColumn><EventDescColumn><ColumnID>13</ColumnID><String>(processpath)</String></EventDescColumn></EventDescColumns></EventDesc><EventDesc><Name>Frame Begin</Name><EventType>5</EventType><EDID>5</EDID><EventDescColumns><EventDescColumn><ColumnID>1</ColumnID><String>(edid)</String></EventDescColumn><EventDescColumn><ColumnID>2</ColumnID><String>CalcOnLoad,Const,5</String></EventDescColumn><EventDescColumn><ColumnID>3</ColumnID><String>(eid)</String></EventDescColumn><EventDescColumn><ColumnID>4</ColumnID><String>(parenteid)</String></EventDescColumn><EventDescColumn><ColumnID>11</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>5</ColumnID><String>(rowflags)</String></EventDescColumn><EventDescColumn><ColumnID>7</ColumnID><String>(time)</String></EventDescColumn><EventDescColumn><ColumnID>9</ColumnID><String>(frame)</String></EventDescColumn><EventDescColumn><ColumnID>6</ColumnID><String>CalcOnLoad,FormatText,1,Frame %d,3,MemberOf,ThisRow,Frame</String></EventDescColumn><EventDescColumn><ColumnID>8</ColumnID><String>Async,(duration)</String></EventDescColumn><EventDescColumn><ColumnID>12</ColumnID><String>CalcOnLoad,Divide,Const,1000000000.0,MemberOf,ThisRow,Duration</String></EventDescColumn><EventDescColumn><ColumnID>21</ColumnID><String>(frameeventfilepos)</String></EventDescColumn><EventDescColumn><ColumnID>22</ColumnID><String>(lastframeeventfilepos)</String></EventDescColumn></EventDescColumns></EventDesc><EventDesc><Name>User Event Begin</Name><EventType>7</EventType><EDID>6</EDID><EventDescColumns><EventDescColumn><ColumnID>1</ColumnID><String>(edid)</String></EventDescColumn><EventDescColumn><ColumnID>2</ColumnID><String>CalcOnLoad,Const,7</String></EventDescColumn><EventDescColumn><ColumnID>3</ColumnID><String>(eid)</String></EventDescColumn><EventDescColumn><ColumnID>4</ColumnID><String>(parenteid)</String></EventDescColumn><EventDescColumn><ColumnID>10</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>11</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>5</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>7</ColumnID><String>(time)</String></EventDescColumn><EventDescColumn><ColumnID>17</ColumnID><String>(usereventname)</String></EventDescColumn><EventDescColumn><ColumnID>6</ColumnID><String>CalcOnLoad,FormatText,1,User Event: %s,1,MemberOf,ThisRow,User Event Name</String></EventDescColumn><EventDescColumn><ColumnID>8</ColumnID><String>Async,(duration)</String></EventDescColumn></EventDescColumns></EventDesc><EventDesc><Name>User Marker</Name><EventType>9</EventType><EDID>7</EDID><EventDescColumns><EventDescColumn><ColumnID>1</ColumnID><String>(edid)</String></EventDescColumn><EventDescColumn><ColumnID>2</ColumnID><String>CalcOnLoad,Const,9</String></EventDescColumn><EventDescColumn><ColumnID>3</ColumnID><String>(eid)</String></EventDescColumn><EventDescColumn><ColumnID>4</ColumnID><String>(parenteid)</String></EventDescColumn><EventDescColumn><ColumnID>10</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>11</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>5</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>7</ColumnID><String>(time)</String></EventDescColumn><EventDescColumn><ColumnID>17</ColumnID><String>(usereventname)</String></EventDescColumn><EventDescColumn><ColumnID>6</ColumnID><String>CalcOnLoad,FormatText,1,User Marker: %s,1,MemberOf,ThisRow,User Event Name</String></EventDescColumn><EventDescColumn><ColumnID>8</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn></EventDescColumns></EventDesc><EventDesc><Name>D3D Call</Name><EventType>10</EventType><EDID>8</EDID><EventDescColumns><EventDescColumn><ColumnID>1</ColumnID><String>(edid)</String></EventDescColumn><EventDescColumn><ColumnID>2</ColumnID><String>CalcOnLoad,Const,10</String></EventDescColumn><EventDescColumn><ColumnID>3</ColumnID><String>(eid)</String></EventDescColumn><EventDescColumn><ColumnID>4</ColumnID><String>(parenteid)</String></EventDescColumn><EventDescColumn><ColumnID>11</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>10</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>5</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>7</ColumnID><String>(time)</String></EventDescColumn><EventDescColumn><ColumnID>6</ColumnID><String>CalcOnLoad,CallPlusParams,MemberOf,ThisRow,PackedCallPackage</String></EventDescColumn><EventDescColumn><ColumnID>19</ColumnID><String>Async,(packedcallpkg)</String></EventDescColumn></EventDescColumns></EventDesc><EventDesc><Name>Object Creation</Name><EventType>11</EventType><EDID>9</EDID><EventDescColumns><EventDescColumn><ColumnID>1</ColumnID><String>(edid)</String></EventDescColumn><EventDescColumn><ColumnID>2</ColumnID><String>CalcOnLoad,Const,11</String></EventDescColumn><EventDescColumn><ColumnID>3</ColumnID><String>(eid)</String></EventDescColumn><EventDescColumn><ColumnID>4</ColumnID><String>(parenteid)</String></EventDescColumn><EventDescColumn><ColumnID>11</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>10</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>5</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>7</ColumnID><String>(time)</String></EventDescColumn><EventDescColumn><ColumnID>6</ColumnID><String>CalcOnLoad,FormatText,0,Object Creation</String></EventDescColumn><EventDescColumn><ColumnID>20</ColumnID><String>(objpointer)</String></EventDescColumn></EventDescColumns></EventDesc><EventDesc><Name>Object Population</Name><EventType>12</EventType><EDID>10</EDID><EventDescColumns><EventDescColumn><ColumnID>1</ColumnID><String>(edid)</String></EventDescColumn><EventDescColumn><ColumnID>2</ColumnID><String>CalcOnLoad,Const,12</String></EventDescColumn><EventDescColumn><ColumnID>3</ColumnID><String>(eid)</String></EventDescColumn><EventDescColumn><ColumnID>4</ColumnID><String>(parenteid)</String></EventDescColumn><EventDescColumn><ColumnID>11</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>10</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>5</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>7</ColumnID><String>(time)</String></EventDescColumn><EventDescColumn><ColumnID>6</ColumnID><String>CalcOnLoad,FormatText,0,Object Population</String></EventDescColumn><EventDescColumn><ColumnID>20</ColumnID><String>(objpointer)</String></EventDescColumn></EventDescColumns></EventDesc><EventDesc><Name>D3D Call (Sync)</Name><EventType>13</EventType><EDID>11</EDID><EventDescColumns><EventDescColumn><ColumnID>1</ColumnID><String>(edid)</String></EventDescColumn><EventDescColumn><ColumnID>2</ColumnID><String>CalcOnLoad,Const,13</String></EventDescColumn><EventDescColumn><ColumnID>3</ColumnID><String>(eid)</String></EventDescColumn><EventDescColumn><ColumnID>4</ColumnID><String>(parenteid)</String></EventDescColumn><EventDescColumn><ColumnID>11</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>10</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>5</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>7</ColumnID><String>(time)</String></EventDescColumn><EventDescColumn><ColumnID>6</ColumnID><String>CalcOnLoad,CallPlusParams,MemberOf,ThisRow,PackedCallPackage</String></EventDescColumn><EventDescColumn><ColumnID>19</ColumnID><String>(packedcallpkg)</String></EventDescColumn></EventDescColumns></EventDesc></EventDescs><Counters/><Triggers><Trigger><Type>1</Type><Recurrence>0</Recurrence><Actions><Action><Type>1</Type><Int1>1</Int1><Str1>import_test</Str1></Action></Actions></Trigger><Trigger><Type>4</Type><Str1>BeginCommandStreamCapture</Str1><Recurrence>1</Recurrence><Actions><Action><Type>3</Type><Int1>1</Int1><Int2>1</Int2></Action></Actions></Trigger><Trigger><Type>4</Type><Str1>EndCommandStreamCapture</Str1><Recurrence>1</Recurrence><Actions><Action><Type>3</Type><Int1>0</Int1><Int2>0</Int2></Action></Actions></Trigger><Trigger><Type>4</Type><Str1>CaptureScreenContents</Str1><Recurrence>1</Recurrence><Actions><Action><Type>4</Type><Int1>19</Int1><Str1>frame_capture</Str1><Str2>.png</Str2></Action></Actions></Trigger></Triggers></PIXExperiment> diff --git a/o3d/tests/testing_framework_reference.PIXExp b/o3d/tests/testing_framework_reference.PIXExp new file mode 100644 index 0000000..5a86d5d --- /dev/null +++ b/o3d/tests/testing_framework_reference.PIXExp @@ -0,0 +1,2 @@ +<?xml version="1.0"?> +<PIXExperiment><Version><ExpFileVersion>202</ExpFileVersion></Version><TargetApp><TargetPath>system_tests.exe</TargetPath><StartFolder></StartFolder><Args></Args><SkipProcesses>0</SkipProcesses><RecordDiagnosticLog>0</RecordDiagnosticLog><IncludeDebugSpew>0</IncludeDebugSpew><DisableD3DXAnalysis>0</DisableD3DXAnalysis></TargetApp><Columns><Column><Name>EDID</Name><ColumnID>1</ColumnID><Flags>0</Flags><Type>3</Type><Format>%d</Format></Column><Column><Name>Event Type</Name><ColumnID>2</ColumnID><Flags>0</Flags><Type>3</Type><Format>%d</Format></Column><Column><Name>EID</Name><ColumnID>3</ColumnID><Flags>0</Flags><Type>3</Type><Format>%d</Format></Column><Column><Name>Parent EID</Name><ColumnID>4</ColumnID><Flags>0</Flags><Type>3</Type><Format>%d</Format></Column><Column><Name>Children</Name><ColumnID>11</ColumnID><Flags>0</Flags><Type>6</Type><Format>%d</Format></Column><Column><Name>Parent</Name><ColumnID>10</ColumnID><Flags>0</Flags><Type>2</Type><Format>%d</Format></Column><Column><Name>Flags</Name><ColumnID>5</ColumnID><Flags>0</Flags><Type>2</Type><Format>0x%08X</Format></Column><Column><Name>Event</Name><ColumnID>6</ColumnID><Flags>0</Flags><Type>4</Type><Format>%s</Format></Column><Column><Name>StartTime</Name><ColumnID>7</ColumnID><Flags>0</Flags><Type>5</Type><Format>%I64i</Format></Column><Column><Name>Path</Name><ColumnID>13</ColumnID><Flags>0</Flags><Type>1</Type><Format>%s</Format></Column><Column><Name>Path2</Name><ColumnID>14</ColumnID><Flags>0</Flags><Type>1</Type><Format>%s</Format></Column><Column><Name>Version</Name><ColumnID>15</ColumnID><Flags>0</Flags><Type>1</Type><Format>%s</Format></Column><Column><Name>TimeLastModified</Name><ColumnID>16</ColumnID><Flags>0</Flags><Type>1</Type><Format>%s</Format></Column><Column><Name>ProcessID</Name><ColumnID>23</ColumnID><Flags>0</Flags><Type>3</Type><Format>%d</Format></Column><Column><Name>SessionStartTimeStamp</Name><ColumnID>24</ColumnID><Flags>0</Flags><Type>5</Type><Format>%I64i</Format></Column><Column><Name>Frame</Name><ColumnID>9</ColumnID><Flags>0</Flags><Type>3</Type><Format>%d</Format></Column><Column><Name>Duration</Name><ColumnID>8</ColumnID><Flags>0</Flags><Type>5</Type><Format>%I64i</Format></Column><Column><Name>FPS</Name><ColumnID>12</ColumnID><Flags>0</Flags><Type>0</Type><Format>%0.01f</Format></Column><Column><Name>ThisEventPos</Name><ColumnID>21</ColumnID><Flags>0</Flags><Type>5</Type><Format>%I64i</Format></Column><Column><Name>NextSiblingPos</Name><ColumnID>22</ColumnID><Flags>0</Flags><Type>5</Type><Format>%I64i</Format></Column><Column><Name>User Event Name</Name><ColumnID>17</ColumnID><Flags>0</Flags><Type>1</Type><Format>%s</Format></Column><Column><Name>PackedCallPackage</Name><ColumnID>19</ColumnID><Flags>0</Flags><Type>7</Type><Format></Format></Column><Column><Name>Object Pointer</Name><ColumnID>20</ColumnID><Flags>0</Flags><Type>2</Type><Format>0x%08X</Format></Column></Columns><EventDescs><EventDesc><Name>Session Start</Name><EventType>1</EventType><EDID>1</EDID><EventDescColumns><EventDescColumn><ColumnID>1</ColumnID><String>(edid)</String></EventDescColumn><EventDescColumn><ColumnID>2</ColumnID><String>CalcOnLoad,Const,1</String></EventDescColumn><EventDescColumn><ColumnID>3</ColumnID><String>(eid)</String></EventDescColumn><EventDescColumn><ColumnID>4</ColumnID><String>CalcOnLoad,Const,-1</String></EventDescColumn><EventDescColumn><ColumnID>5</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>7</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>8</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>6</ColumnID><String>CalcOnLoad,FormatText,0,Start Session</String></EventDescColumn><EventDescColumn><ColumnID>13</ColumnID><String>(expfilepath)</String></EventDescColumn><EventDescColumn><ColumnID>14</ColumnID><String>(runfilepath)</String></EventDescColumn><EventDescColumn><ColumnID>24</ColumnID><String>(sessionstarttimestamp)</String></EventDescColumn></EventDescColumns></EventDesc><EventDesc><Name>Session End</Name><EventType>2</EventType><EDID>2</EDID><EventDescColumns><EventDescColumn><ColumnID>1</ColumnID><String>(edid)</String></EventDescColumn><EventDescColumn><ColumnID>2</ColumnID><String>CalcOnLoad,Const,2</String></EventDescColumn><EventDescColumn><ColumnID>3</ColumnID><String>(eid)</String></EventDescColumn><EventDescColumn><ColumnID>4</ColumnID><String>CalcOnLoad,Const,-1</String></EventDescColumn><EventDescColumn><ColumnID>5</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>7</ColumnID><String>(time)</String></EventDescColumn><EventDescColumn><ColumnID>8</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>6</ColumnID><String>CalcOnLoad,FormatText,0,End Session</String></EventDescColumn></EventDescColumns></EventDesc><EventDesc><Name>Process Start</Name><EventType>3</EventType><EDID>3</EDID><EventDescColumns><EventDescColumn><ColumnID>1</ColumnID><String>(edid)</String></EventDescColumn><EventDescColumn><ColumnID>2</ColumnID><String>CalcOnLoad,Const,3</String></EventDescColumn><EventDescColumn><ColumnID>3</ColumnID><String>(eid)</String></EventDescColumn><EventDescColumn><ColumnID>4</ColumnID><String>CalcOnLoad,Const,-1</String></EventDescColumn><EventDescColumn><ColumnID>5</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>7</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>8</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>6</ColumnID><String>CalcOnLoad,FormatText,0,Start Process</String></EventDescColumn><EventDescColumn><ColumnID>13</ColumnID><String>(processpath)</String></EventDescColumn><EventDescColumn><ColumnID>15</ColumnID><String>(processversion)</String></EventDescColumn><EventDescColumn><ColumnID>16</ColumnID><String>(processtimelastmodified)</String></EventDescColumn><EventDescColumn><ColumnID>23</ColumnID><String>(processid)</String></EventDescColumn></EventDescColumns></EventDesc><EventDesc><Name>Process End</Name><EventType>4</EventType><EDID>4</EDID><EventDescColumns><EventDescColumn><ColumnID>1</ColumnID><String>(edid)</String></EventDescColumn><EventDescColumn><ColumnID>2</ColumnID><String>CalcOnLoad,Const,4</String></EventDescColumn><EventDescColumn><ColumnID>3</ColumnID><String>(eid)</String></EventDescColumn><EventDescColumn><ColumnID>4</ColumnID><String>CalcOnLoad,Const,-1</String></EventDescColumn><EventDescColumn><ColumnID>5</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>7</ColumnID><String>(time)</String></EventDescColumn><EventDescColumn><ColumnID>8</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>6</ColumnID><String>CalcOnLoad,FormatText,0,End Process</String></EventDescColumn><EventDescColumn><ColumnID>13</ColumnID><String>(processpath)</String></EventDescColumn></EventDescColumns></EventDesc><EventDesc><Name>Frame Begin</Name><EventType>5</EventType><EDID>5</EDID><EventDescColumns><EventDescColumn><ColumnID>1</ColumnID><String>(edid)</String></EventDescColumn><EventDescColumn><ColumnID>2</ColumnID><String>CalcOnLoad,Const,5</String></EventDescColumn><EventDescColumn><ColumnID>3</ColumnID><String>(eid)</String></EventDescColumn><EventDescColumn><ColumnID>4</ColumnID><String>(parenteid)</String></EventDescColumn><EventDescColumn><ColumnID>11</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>5</ColumnID><String>(rowflags)</String></EventDescColumn><EventDescColumn><ColumnID>7</ColumnID><String>(time)</String></EventDescColumn><EventDescColumn><ColumnID>9</ColumnID><String>(frame)</String></EventDescColumn><EventDescColumn><ColumnID>6</ColumnID><String>CalcOnLoad,FormatText,1,Frame %d,3,MemberOf,ThisRow,Frame</String></EventDescColumn><EventDescColumn><ColumnID>8</ColumnID><String>Async,(duration)</String></EventDescColumn><EventDescColumn><ColumnID>12</ColumnID><String>CalcOnLoad,Divide,Const,1000000000.0,MemberOf,ThisRow,Duration</String></EventDescColumn><EventDescColumn><ColumnID>21</ColumnID><String>(frameeventfilepos)</String></EventDescColumn><EventDescColumn><ColumnID>22</ColumnID><String>(lastframeeventfilepos)</String></EventDescColumn></EventDescColumns></EventDesc><EventDesc><Name>User Event Begin</Name><EventType>7</EventType><EDID>6</EDID><EventDescColumns><EventDescColumn><ColumnID>1</ColumnID><String>(edid)</String></EventDescColumn><EventDescColumn><ColumnID>2</ColumnID><String>CalcOnLoad,Const,7</String></EventDescColumn><EventDescColumn><ColumnID>3</ColumnID><String>(eid)</String></EventDescColumn><EventDescColumn><ColumnID>4</ColumnID><String>(parenteid)</String></EventDescColumn><EventDescColumn><ColumnID>10</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>11</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>5</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>7</ColumnID><String>(time)</String></EventDescColumn><EventDescColumn><ColumnID>17</ColumnID><String>(usereventname)</String></EventDescColumn><EventDescColumn><ColumnID>6</ColumnID><String>CalcOnLoad,FormatText,1,User Event: %s,1,MemberOf,ThisRow,User Event Name</String></EventDescColumn><EventDescColumn><ColumnID>8</ColumnID><String>Async,(duration)</String></EventDescColumn></EventDescColumns></EventDesc><EventDesc><Name>User Marker</Name><EventType>9</EventType><EDID>7</EDID><EventDescColumns><EventDescColumn><ColumnID>1</ColumnID><String>(edid)</String></EventDescColumn><EventDescColumn><ColumnID>2</ColumnID><String>CalcOnLoad,Const,9</String></EventDescColumn><EventDescColumn><ColumnID>3</ColumnID><String>(eid)</String></EventDescColumn><EventDescColumn><ColumnID>4</ColumnID><String>(parenteid)</String></EventDescColumn><EventDescColumn><ColumnID>10</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>11</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>5</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>7</ColumnID><String>(time)</String></EventDescColumn><EventDescColumn><ColumnID>17</ColumnID><String>(usereventname)</String></EventDescColumn><EventDescColumn><ColumnID>6</ColumnID><String>CalcOnLoad,FormatText,1,User Marker: %s,1,MemberOf,ThisRow,User Event Name</String></EventDescColumn><EventDescColumn><ColumnID>8</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn></EventDescColumns></EventDesc><EventDesc><Name>D3D Call</Name><EventType>10</EventType><EDID>8</EDID><EventDescColumns><EventDescColumn><ColumnID>1</ColumnID><String>(edid)</String></EventDescColumn><EventDescColumn><ColumnID>2</ColumnID><String>CalcOnLoad,Const,10</String></EventDescColumn><EventDescColumn><ColumnID>3</ColumnID><String>(eid)</String></EventDescColumn><EventDescColumn><ColumnID>4</ColumnID><String>(parenteid)</String></EventDescColumn><EventDescColumn><ColumnID>11</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>10</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>5</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>7</ColumnID><String>(time)</String></EventDescColumn><EventDescColumn><ColumnID>6</ColumnID><String>CalcOnLoad,CallPlusParams,MemberOf,ThisRow,PackedCallPackage</String></EventDescColumn><EventDescColumn><ColumnID>19</ColumnID><String>Async,(packedcallpkg)</String></EventDescColumn></EventDescColumns></EventDesc><EventDesc><Name>Object Creation</Name><EventType>11</EventType><EDID>9</EDID><EventDescColumns><EventDescColumn><ColumnID>1</ColumnID><String>(edid)</String></EventDescColumn><EventDescColumn><ColumnID>2</ColumnID><String>CalcOnLoad,Const,11</String></EventDescColumn><EventDescColumn><ColumnID>3</ColumnID><String>(eid)</String></EventDescColumn><EventDescColumn><ColumnID>4</ColumnID><String>(parenteid)</String></EventDescColumn><EventDescColumn><ColumnID>11</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>10</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>5</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>7</ColumnID><String>(time)</String></EventDescColumn><EventDescColumn><ColumnID>6</ColumnID><String>CalcOnLoad,FormatText,0,Object Creation</String></EventDescColumn><EventDescColumn><ColumnID>20</ColumnID><String>(objpointer)</String></EventDescColumn></EventDescColumns></EventDesc><EventDesc><Name>Object Population</Name><EventType>12</EventType><EDID>10</EDID><EventDescColumns><EventDescColumn><ColumnID>1</ColumnID><String>(edid)</String></EventDescColumn><EventDescColumn><ColumnID>2</ColumnID><String>CalcOnLoad,Const,12</String></EventDescColumn><EventDescColumn><ColumnID>3</ColumnID><String>(eid)</String></EventDescColumn><EventDescColumn><ColumnID>4</ColumnID><String>(parenteid)</String></EventDescColumn><EventDescColumn><ColumnID>11</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>10</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>5</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>7</ColumnID><String>(time)</String></EventDescColumn><EventDescColumn><ColumnID>6</ColumnID><String>CalcOnLoad,FormatText,0,Object Population</String></EventDescColumn><EventDescColumn><ColumnID>20</ColumnID><String>(objpointer)</String></EventDescColumn></EventDescColumns></EventDesc><EventDesc><Name>D3D Call (Sync)</Name><EventType>13</EventType><EDID>11</EDID><EventDescColumns><EventDescColumn><ColumnID>1</ColumnID><String>(edid)</String></EventDescColumn><EventDescColumn><ColumnID>2</ColumnID><String>CalcOnLoad,Const,13</String></EventDescColumn><EventDescColumn><ColumnID>3</ColumnID><String>(eid)</String></EventDescColumn><EventDescColumn><ColumnID>4</ColumnID><String>(parenteid)</String></EventDescColumn><EventDescColumn><ColumnID>11</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>10</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>5</ColumnID><String>CalcOnLoad,Const,0</String></EventDescColumn><EventDescColumn><ColumnID>7</ColumnID><String>(time)</String></EventDescColumn><EventDescColumn><ColumnID>6</ColumnID><String>CalcOnLoad,CallPlusParams,MemberOf,ThisRow,PackedCallPackage</String></EventDescColumn><EventDescColumn><ColumnID>19</ColumnID><String>(packedcallpkg)</String></EventDescColumn></EventDescColumns></EventDesc></EventDescs><Counters/><Triggers><Trigger><Type>1</Type><Recurrence>0</Recurrence><Actions><Action><Type>1</Type><Int1>1</Int1><Str1>import_test</Str1></Action><Action><Type>5</Type><Int1>1</Int1></Action></Actions></Trigger><Trigger><Type>4</Type><Str1>BeginCommandStreamCapture</Str1><Recurrence>1</Recurrence><Actions><Action><Type>3</Type><Int1>1</Int1><Int2>1</Int2></Action></Actions></Trigger><Trigger><Type>4</Type><Str1>EndCommandStreamCapture</Str1><Recurrence>1</Recurrence><Actions><Action><Type>3</Type><Int1>0</Int1><Int2>0</Int2></Action></Actions></Trigger><Trigger><Type>4</Type><Str1>CaptureScreenContents</Str1><Recurrence>1</Recurrence><Actions><Action><Type>4</Type><Int1>19</Int1><Str1>frame_capture</Str1><Str2>.png</Str2></Action></Actions></Trigger></Triggers></PIXExperiment> |