From 6d56b1d38a1a40d8606dfbdff80dfa7311a66efe Mon Sep 17 00:00:00 2001 From: Emil Axelsson Date: Fri, 19 Aug 2016 16:56:57 +0200 Subject: [PATCH 01/92] implement shadow mapping for image projections on non-convex bodies --- data/scene/rosetta/67P/67P.mod | 5 +- .../rendering/renderablemodelprojection.cpp | 52 +++++++-- .../rendering/renderablemodelprojection.h | 2 +- .../rendering/renderableplanetprojection.cpp | 13 ++- .../shaders/renderableModelDepth_fs.glsl | 30 +++++ .../shaders/renderableModelDepth_vs.glsl | 36 ++++++ .../shaders/renderableModelProjection_fs.glsl | 33 +++--- .../shaders/renderableModelProjection_vs.glsl | 16 +-- .../newhorizons/util/projectioncomponent.cpp | 110 ++++++++++++++---- .../newhorizons/util/projectioncomponent.h | 13 ++- 10 files changed, 240 insertions(+), 70 deletions(-) create mode 100644 modules/newhorizons/shaders/renderableModelDepth_fs.glsl create mode 100644 modules/newhorizons/shaders/renderableModelDepth_vs.glsl diff --git a/data/scene/rosetta/67P/67P.mod b/data/scene/rosetta/67P/67P.mod index a6ec406f4c..e925538385 100644 --- a/data/scene/rosetta/67P/67P.mod +++ b/data/scene/rosetta/67P/67P.mod @@ -62,10 +62,9 @@ return { Method = "ELLIPSOID", Aberration = "NONE", Fovy = 5.00, - Aspect = 1, - Near = 0.01, - Far = 1000000, + Aspect = 1 }, + BoundingSphereRadius = 5000.0 }, Ephemeris = { diff --git a/modules/newhorizons/rendering/renderablemodelprojection.cpp b/modules/newhorizons/rendering/renderablemodelprojection.cpp index 477e2b62ca..5f0adfa4db 100644 --- a/modules/newhorizons/rendering/renderablemodelprojection.cpp +++ b/modules/newhorizons/rendering/renderablemodelprojection.cpp @@ -40,6 +40,7 @@ namespace { const std::string keyDestination = "Rotation.Destination"; const std::string keyBody = "Body"; const std::string keyGeometry = "Geometry"; + const std::string keyBoundingSphereRadius = "BoundingSphereRadius"; const std::string keyTextureColor = "Textures.Color"; const std::string keyTextureProject = "Textures.Project"; @@ -97,7 +98,10 @@ RenderableModelProjection::RenderableModelProjection(const ghoul::Dictionary& di completeSuccess &= _projectionComponent.initializeProjectionSettings(dictionary); openspace::SpiceManager::ref().addFrame(_target, _source); - setBoundingSphere(pss(1.f, 9.f)); + + float boundingSphereRadius = 1.0e9; + dictionary.getValue(keyBoundingSphereRadius, boundingSphereRadius); + setBoundingSphere(PowerScaledScalar::CreatePSS(boundingSphereRadius)); Renderable::addProperty(_performShading); Renderable::addProperty(_rotation); @@ -130,11 +134,20 @@ bool RenderableModelProjection::initialize() { ghoul::opengl::ProgramObject::IgnoreError::Yes ); + _depthFboProgramObject = ghoul::opengl::ProgramObject::Build("DepthPass", + "${MODULE_NEWHORIZONS}/shaders/renderableModelDepth_vs.glsl", + "${MODULE_NEWHORIZONS}/shaders/renderableModelDepth_fs.glsl"); + + completeSuccess &= loadTextures(); completeSuccess &= _projectionComponent.initialize(); + + auto bs = getBoundingSphere(); completeSuccess &= _geometry->initialize(this); + setBoundingSphere(bs); // ignore bounding sphere set by geometry. + completeSuccess &= !_source.empty(); completeSuccess &= !_destination.empty(); @@ -164,7 +177,6 @@ void RenderableModelProjection::render(const RenderData& data) { if (_projectionComponent.needsClearProjection()) _projectionComponent.clearAllProjections(); - _camScaling = data.camera.scaling(); _up = data.camera.lookUpVectorCameraSpace(); if (_capture && _projectionComponent.doesPerformProjection()) @@ -205,6 +217,9 @@ void RenderableModelProjection::update(const UpdateData& data) { if (_fboProgramObject->isDirty()) _fboProgramObject->rebuildFromFile(); + if (_depthFboProgramObject->isDirty()) + _depthFboProgramObject->rebuildFromFile(); + _time = data.time; if (openspace::ImageSequencer::ref().isReady()) { @@ -236,8 +251,18 @@ void RenderableModelProjection::update(const UpdateData& data) { void RenderableModelProjection::imageProjectGPU( std::shared_ptr projectionTexture) { - _projectionComponent.imageProjectBegin(); + _projectionComponent.depthMapRenderBegin(); + _depthFboProgramObject->activate(); + _depthFboProgramObject->setUniform("ProjectorMatrix", _projectorMatrix); + _depthFboProgramObject->setUniform("ModelTransform", _transform); + _geometry->setUniforms(*_fboProgramObject); + _geometry->render(); + + _depthFboProgramObject->deactivate(); + _projectionComponent.depthMapRenderEnd(); + + _projectionComponent.imageProjectBegin(); _fboProgramObject->activate(); ghoul::opengl::TextureUnit unitFbo; @@ -245,9 +270,17 @@ void RenderableModelProjection::imageProjectGPU( projectionTexture->bind(); _fboProgramObject->setUniform("projectionTexture", unitFbo); + ghoul::opengl::TextureUnit unitDepthFbo; + unitDepthFbo.activate(); + _projectionComponent.depthTexture().bind(); + _fboProgramObject->setUniform("depthTexture", unitDepthFbo); + + glm::vec4 debugVector(0.0, 0.0, 0.0, 1.0); + glm::vec4 debugTransformed = _projectorMatrix * _transform * debugVector; + debugTransformed /= debugTransformed.w; + _fboProgramObject->setUniform("ProjectorMatrix", _projectorMatrix); _fboProgramObject->setUniform("ModelTransform", _transform); - _fboProgramObject->setUniform("_scaling", _camScaling); _fboProgramObject->setUniform("boresight", _boresight); _geometry->setUniforms(*_fboProgramObject); @@ -309,19 +342,24 @@ void RenderableModelProjection::attitudeParameters(double time) { time, lightTime); psc position = PowerScaledCoordinate::CreatePowerScaledCoordinate(p.x, p.y, p.z); - position[3] += (3 + _camScaling[1]); + position[3] += 3; glm::vec3 cpos = position.vec3(); + float distance = glm::length(cpos); + float radius = getBoundingSphere().lengthf(); + _projectorMatrix = _projectionComponent.computeProjectorMatrix( cpos, boresight, _up, _instrumentMatrix, _projectionComponent.fieldOfViewY(), _projectionComponent.aspectRatio(), - _projectionComponent.nearPlane(), - _projectionComponent.farPlane(), + distance - radius, + distance + radius, _boresight ); } + + void RenderableModelProjection::project() { for (auto img : _imageTimes) { attitudeParameters(img.startTime); diff --git a/modules/newhorizons/rendering/renderablemodelprojection.h b/modules/newhorizons/rendering/renderablemodelprojection.h index 644af7b905..e91d8c1283 100644 --- a/modules/newhorizons/rendering/renderablemodelprojection.h +++ b/modules/newhorizons/rendering/renderablemodelprojection.h @@ -74,6 +74,7 @@ private: std::unique_ptr _programObject; std::unique_ptr _fboProgramObject; + std::unique_ptr _depthFboProgramObject; std::unique_ptr _baseTexture; @@ -100,7 +101,6 @@ private: bool _capture; psc _sunPosition; - properties::BoolProperty _performShading; }; diff --git a/modules/newhorizons/rendering/renderableplanetprojection.cpp b/modules/newhorizons/rendering/renderableplanetprojection.cpp index 13516f1e5f..727bfefbe5 100644 --- a/modules/newhorizons/rendering/renderableplanetprojection.cpp +++ b/modules/newhorizons/rendering/renderableplanetprojection.cpp @@ -47,6 +47,7 @@ namespace { const std::string keyFrame = "Frame"; const std::string keyGeometry = "Geometry"; + const std::string keyRadius = "Geometry.Radius"; const std::string keyShading = "PerformShading"; const std::string keyBody = "Body"; const std::string _mainFrame = "GALACTIC"; @@ -103,6 +104,10 @@ RenderablePlanetProjection::RenderablePlanetProjection(const ghoul::Dictionary& if (success) _heightMapTexturePath = absPath(heightMapPath); + glm::vec2 radius = glm::vec2(1.0, 9.0); + dictionary.getValue(keyRadius, radius); + setBoundingSphere(pss(radius)); + addPropertySubOwner(_geometry.get()); addPropertySubOwner(_projectionComponent); @@ -136,7 +141,6 @@ bool RenderablePlanetProjection::initialize() { completeSuccess &= loadTextures(); completeSuccess &= _projectionComponent.initialize(); - completeSuccess &= _geometry->initialize(this); if (completeSuccess) { @@ -287,6 +291,9 @@ void RenderablePlanetProjection::attitudeParameters(double time) { //position[3] += 3; glm::vec3 cpos = position.vec3(); + float distance = glm::length(cpos); + float radius = getBoundingSphere().lengthf(); + _projectorMatrix = _projectionComponent.computeProjectorMatrix( cpos, bs, @@ -294,8 +301,8 @@ void RenderablePlanetProjection::attitudeParameters(double time) { _instrumentMatrix, _projectionComponent.fieldOfViewY(), _projectionComponent.aspectRatio(), - _projectionComponent.nearPlane(), - _projectionComponent.farPlane(), + distance - radius, + distance + radius, _boresight ); } diff --git a/modules/newhorizons/shaders/renderableModelDepth_fs.glsl b/modules/newhorizons/shaders/renderableModelDepth_fs.glsl new file mode 100644 index 0000000000..2b7bcfdaec --- /dev/null +++ b/modules/newhorizons/shaders/renderableModelDepth_fs.glsl @@ -0,0 +1,30 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#version __CONTEXT__ + +void main() { + gl_FragColor = vec4(1.0); + //gl_FragDepth = gl_FragCoord.z; +} diff --git a/modules/newhorizons/shaders/renderableModelDepth_vs.glsl b/modules/newhorizons/shaders/renderableModelDepth_vs.glsl new file mode 100644 index 0000000000..574a349ad4 --- /dev/null +++ b/modules/newhorizons/shaders/renderableModelDepth_vs.glsl @@ -0,0 +1,36 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#version __CONTEXT__ + +#include "PowerScaling/powerScaling_vs.hglsl" + +layout(location = 0) in vec4 in_position; + +uniform mat4 ProjectorMatrix; +uniform mat4 ModelTransform; + +void main() { + gl_Position = ProjectorMatrix * ModelTransform * psc_to_meter(in_position, vec2(1.0, 0.0)); +} diff --git a/modules/newhorizons/shaders/renderableModelProjection_fs.glsl b/modules/newhorizons/shaders/renderableModelProjection_fs.glsl index 0d0bcbec89..9f052c5889 100644 --- a/modules/newhorizons/shaders/renderableModelProjection_fs.glsl +++ b/modules/newhorizons/shaders/renderableModelProjection_fs.glsl @@ -24,42 +24,41 @@ #version __CONTEXT__ +#include "PowerScaling/powerScalingMath.hglsl" #include "PowerScaling/powerScaling_vs.hglsl" + in vec4 vs_position; +in vec4 vs_ndc; in vec4 vs_normal; -in vec2 vs_uv; -in vec4 ProjTexCoord; out vec4 color; uniform sampler2D projectionTexture; +uniform sampler2D depthTexture; uniform mat4 ModelTransform; -uniform vec2 _scaling; uniform vec3 boresight; +uniform vec4 debugColor; bool inRange(float x, float a, float b) { return (x >= a && x <= b); } void main() { - vec2 uv = vec2(0.5,0.5)*vs_uv+vec2(0.5,0.5); - vec3 n = normalize(vs_normal.xyz); - vec4 projected = ProjTexCoord; + vec4 projected = vs_ndc; + vec2 uv = vec2(0.5) * projected.xy + vec2(0.5); - //normalize - projected.x /= projected.w; - projected.y /= projected.w; - //invert gl coordinates - projected.x = 1 - projected.x; - - if ((inRange(projected.x, 0, 1) && inRange(projected.y, 0, 1)) && (dot(n, boresight) < 0)) { - color = texture(projectionTexture, projected.xy); + float thisDepth = projected.z * 0.5 + 0.5; + float closestDepth = texture(depthTexture, uv).r; + float epsilon = 0.001; + + if (inRange(uv.x, 0.0, 1.0) && inRange(uv.y, 0.0, 1.0) && + dot(n, boresight) < 0 && thisDepth <= closestDepth + epsilon) { + color = texture(projectionTexture, uv); color.a = 1.0; - } - else { - color = vec4(vec3(0.0), 1.0); + } else { + color = vec4(vec3(0.0), 0.0); } } diff --git a/modules/newhorizons/shaders/renderableModelProjection_vs.glsl b/modules/newhorizons/shaders/renderableModelProjection_vs.glsl index 20c64bd812..2be32b0119 100644 --- a/modules/newhorizons/shaders/renderableModelProjection_vs.glsl +++ b/modules/newhorizons/shaders/renderableModelProjection_vs.glsl @@ -33,26 +33,20 @@ layout(location = 2) in vec3 in_normal; out vec4 vs_position; out vec4 vs_normal; out vec2 vs_uv; -out vec4 ProjTexCoord; +out vec4 vs_ndc; uniform mat4 ProjectorMatrix; uniform mat4 ModelTransform; -uniform vec2 _scaling; uniform vec3 boresight; void main() { - vs_position = in_position; - - vec4 tmp = in_position; - vec4 position = pscTransform(tmp, ModelTransform); - vs_position = position; - - vec4 raw_pos = psc_to_meter(in_position, _scaling); - ProjTexCoord = ProjectorMatrix * ModelTransform * raw_pos; + vec4 raw_pos = psc_to_meter(in_position, vec2(1.0, 0.0)); + vs_position = ProjectorMatrix * ModelTransform * raw_pos; vs_normal = normalize(ModelTransform * vec4(in_normal,0)); - + vs_ndc = vs_position / vs_position.w; + //match clipping plane vec2 texco = (in_st * 2) - 1; vs_uv = texco; diff --git a/modules/newhorizons/util/projectioncomponent.cpp b/modules/newhorizons/util/projectioncomponent.cpp index 56548b1d88..048eb1bf7a 100644 --- a/modules/newhorizons/util/projectioncomponent.cpp +++ b/modules/newhorizons/util/projectioncomponent.cpp @@ -41,8 +41,6 @@ namespace { const std::string keyInstrument = "Instrument.Name"; const std::string keyInstrumentFovy = "Instrument.Fovy"; const std::string keyInstrumentAspect = "Instrument.Aspect"; - const std::string keyInstrumentNear = "Instrument.Near"; - const std::string keyInstrumentFar = "Instrument.Far"; const std::string keyProjObserver = "Projection.Observer"; const std::string keyProjTarget = "Projection.Target"; @@ -81,8 +79,10 @@ ProjectionComponent::ProjectionComponent() } bool ProjectionComponent::initialize() { - bool a = generateProjectionLayerTexture(); - bool b = auxiliaryRendertarget(); + bool success = generateProjectionLayerTexture(); + success &= generateDepthTexture(); + success &= auxiliaryRendertarget(); + success &= depthRendertarget(); using std::unique_ptr; using ghoul::opengl::Texture; @@ -98,7 +98,7 @@ bool ProjectionComponent::initialize() { } _placeholderTexture = std::move(texture); - return a && b; + return success; } bool ProjectionComponent::deinitialize() { @@ -120,8 +120,7 @@ bool ProjectionComponent::initializeProjectionSettings(const Dictionary& diction completeSuccess &= dictionary.getValue(keyProjTarget, _projecteeID); completeSuccess &= dictionary.getValue(keyInstrumentFovy, _fovy); completeSuccess &= dictionary.getValue(keyInstrumentAspect, _aspectRatio); - completeSuccess &= dictionary.getValue(keyInstrumentNear, _nearPlane); - completeSuccess &= dictionary.getValue(keyInstrumentFar, _farPlane); + ghoul_assert(completeSuccess, "All neccessary attributes not found in modfile"); std::string a = "NONE"; @@ -227,11 +226,63 @@ void ProjectionComponent::imageProjectBegin() { ); } +ghoul::opengl::Texture& ProjectionComponent::depthTexture() { + return *_depthTexture; +} + +void ProjectionComponent::depthMapRenderBegin() { + // keep handle to the current bound FBO + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_defaultFBO); + glGetIntegerv(GL_VIEWPORT, _viewport); + + glBindFramebuffer(GL_FRAMEBUFFER, _depthFboID); + glEnable(GL_DEPTH_TEST); + + glViewport( + 0, 0, + static_cast(_depthTexture->width()), + static_cast(_depthTexture->height()) + ); + + glClear(GL_DEPTH_BUFFER_BIT); +} + +void ProjectionComponent::depthMapRenderEnd() { + glBindFramebuffer(GL_FRAMEBUFFER, _defaultFBO); + glViewport(_viewport[0], _viewport[1], _viewport[2], _viewport[3]); +} + + + void ProjectionComponent::imageProjectEnd() { glBindFramebuffer(GL_FRAMEBUFFER, _defaultFBO); glViewport(_viewport[0], _viewport[1], _viewport[2], _viewport[3]); } + +bool ProjectionComponent::depthRendertarget() { + GLint defaultFBO; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO); + // setup FBO + glGenFramebuffers(1, &_depthFboID); + glBindFramebuffer(GL_FRAMEBUFFER, _depthFboID); + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + GL_TEXTURE_2D, + *_depthTexture, + 0); + + glDrawBuffer(GL_NONE); + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) + return false; + + glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO); + return true; +} + bool ProjectionComponent::auxiliaryRendertarget() { bool completeSuccess = true; @@ -266,26 +317,27 @@ glm::mat4 ProjectionComponent::computeProjectorMatrix(const glm::vec3 loc, glm:: float nearPlane, float farPlane, glm::vec3& boreSight) { + //rotate boresight into correct alignment boreSight = instrumentMatrix*aim; glm::vec3 uptmp(instrumentMatrix*glm::dvec3(up)); // create view matrix - glm::vec3 e3 = glm::normalize(boreSight); + glm::vec3 e3 = glm::normalize(-boreSight); glm::vec3 e1 = glm::normalize(glm::cross(uptmp, e3)); glm::vec3 e2 = glm::normalize(glm::cross(e3, e1)); + + + + glm::mat4 projViewMatrix = glm::mat4(e1.x, e2.x, e3.x, 0.f, e1.y, e2.y, e3.y, 0.f, e1.z, e2.z, e3.z, 0.f, - -glm::dot(e1, loc), -glm::dot(e2, loc), -glm::dot(e3, loc), 1.f); + glm::dot(e1, -loc), glm::dot(e2, -loc), glm::dot(e3, -loc), 1.f); // create perspective projection matrix glm::mat4 projProjectionMatrix = glm::perspective(glm::radians(fieldOfViewY), aspectRatio, nearPlane, farPlane); - // bias matrix - glm::mat4 projNormalizationMatrix = glm::mat4(0.5f, 0, 0, 0, - 0, 0.5f, 0, 0, - 0, 0, 0.5f, 0, - 0.5f, 0.5f, 0.5f, 1); - return projNormalizationMatrix*projProjectionMatrix*projViewMatrix; + + return projProjectionMatrix*projViewMatrix; } bool ProjectionComponent::doesPerformProjection() const { @@ -328,14 +380,6 @@ float ProjectionComponent::aspectRatio() const { return _aspectRatio; } -float ProjectionComponent::nearPlane() const { - return _nearPlane; -} - -float ProjectionComponent::farPlane() const { - return _farPlane; -} - void ProjectionComponent::clearAllProjections() { // keep handle to the current bound FBO GLint defaultFBO; @@ -402,4 +446,24 @@ bool ProjectionComponent::generateProjectionLayerTexture() { } +bool ProjectionComponent::generateDepthTexture() { + int maxSize = OpenGLCap.max2DTextureSize() / 2; + + LINFO( + "Creating depth texture of size '" << maxSize / 2 << ", " << maxSize / 2 << "'" + ); + + _depthTexture = std::make_unique( + glm::uvec3(maxSize / 2, maxSize / 2, 1), + ghoul::opengl::Texture::Format::DepthComponent, + GL_DEPTH_COMPONENT32F + ); + + if (_depthTexture) + _depthTexture->uploadTexture(); + + return _depthTexture != nullptr; + +} + } // namespace openspace diff --git a/modules/newhorizons/util/projectioncomponent.h b/modules/newhorizons/util/projectioncomponent.h index 197a886dc4..34aa7a5225 100644 --- a/modules/newhorizons/util/projectioncomponent.h +++ b/modules/newhorizons/util/projectioncomponent.h @@ -46,11 +46,17 @@ public: bool initializeProjectionSettings(const ghoul::Dictionary& dictionary); bool initializeParser(const ghoul::Dictionary& dictionary); + ghoul::opengl::Texture& ProjectionComponent::depthTexture(); void imageProjectBegin(); void imageProjectEnd(); + void depthMapRenderBegin(); + void depthMapRenderEnd(); + bool generateProjectionLayerTexture(); + bool generateDepthTexture(); bool auxiliaryRendertarget(); + bool depthRendertarget(); std::shared_ptr loadProjectionTexture( const std::string& texturePath, @@ -82,8 +88,6 @@ public: float fieldOfViewY() const; float aspectRatio() const; - float nearPlane() const; - float farPlane() const; protected: properties::BoolProperty _performProjection; @@ -91,7 +95,7 @@ protected: properties::FloatProperty _projectionFading; std::unique_ptr _projectionTexture; - + std::unique_ptr _depthTexture; std::shared_ptr _placeholderTexture; std::string _instrumentID; @@ -101,10 +105,9 @@ protected: std::vector _potentialTargets; float _fovy; float _aspectRatio; - float _nearPlane; - float _farPlane; GLuint _fboID; + GLuint _depthFboID; GLint _defaultFBO; GLint _viewport[4]; From 3d000a5bb13ede78c0f0c8a45501fbad125147e4 Mon Sep 17 00:00:00 2001 From: Emil Axelsson Date: Wed, 24 Aug 2016 11:38:32 +0200 Subject: [PATCH 02/92] flip texture access to correct projection error --- modules/newhorizons/shaders/renderableModelProjection_fs.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/newhorizons/shaders/renderableModelProjection_fs.glsl b/modules/newhorizons/shaders/renderableModelProjection_fs.glsl index 9f052c5889..1cf1c09c94 100644 --- a/modules/newhorizons/shaders/renderableModelProjection_fs.glsl +++ b/modules/newhorizons/shaders/renderableModelProjection_fs.glsl @@ -56,7 +56,7 @@ void main() { if (inRange(uv.x, 0.0, 1.0) && inRange(uv.y, 0.0, 1.0) && dot(n, boresight) < 0 && thisDepth <= closestDepth + epsilon) { - color = texture(projectionTexture, uv); + color = texture(projectionTexture, vec2(1.0) - uv); color.a = 1.0; } else { color = vec4(vec3(0.0), 0.0); From d0ec7ac73566a14a6b2e11bdb3c58568a3ce4d5d Mon Sep 17 00:00:00 2001 From: Emil Axelsson Date: Thu, 25 Aug 2016 16:32:27 +0200 Subject: [PATCH 03/92] render trails with additive blending --- modules/base/rendering/renderabletrail.cpp | 14 ++++++++++++++ modules/base/shaders/ephemeris_fs.glsl | 3 ++- shaders/abuffer/renderabuffer.frag | 17 +++++++++++++---- shaders/abuffer/resolveabuffer.frag | 2 +- 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/modules/base/rendering/renderabletrail.cpp b/modules/base/rendering/renderabletrail.cpp index b41a42e13d..265321f8ae 100644 --- a/modules/base/rendering/renderabletrail.cpp +++ b/modules/base/rendering/renderabletrail.cpp @@ -179,6 +179,14 @@ void RenderableTrail::render(const RenderData& data) { // _programObject->setUniform("forceFade", _distanceFade); //} + bool usingFramebufferRenderer = + OsEng.renderEngine().rendererImplementation() == RenderEngine::RendererImplementation::Framebuffer; + + if (usingFramebufferRenderer) { + glDepthMask(false); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + } + glLineWidth(_lineWidth); glBindVertexArray(_vaoID); @@ -194,6 +202,12 @@ void RenderableTrail::render(const RenderData& data) { glBindVertexArray(0); } + + if (usingFramebufferRenderer) { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDepthMask(true); + } + _programObject->deactivate(); } diff --git a/modules/base/shaders/ephemeris_fs.glsl b/modules/base/shaders/ephemeris_fs.glsl index 49453927c1..26b9de2d89 100644 --- a/modules/base/shaders/ephemeris_fs.glsl +++ b/modules/base/shaders/ephemeris_fs.glsl @@ -36,10 +36,11 @@ Fragment getFragment() { vec4 position = vs_point_position; float depth = pscDepth(position); - vec4 c = vec4(color, fade*forceFade); + vec4 c = vec4(color * fade * forceFade, 1.0); Fragment frag; frag.color = c; frag.depth = depth; + frag.blend = BLEND_MODE_ADDITIVE; return frag; } diff --git a/shaders/abuffer/renderabuffer.frag b/shaders/abuffer/renderabuffer.frag index d3abc97ddf..0dfd046983 100644 --- a/shaders/abuffer/renderabuffer.frag +++ b/shaders/abuffer/renderabuffer.frag @@ -36,10 +36,19 @@ void main() { if (frag.depth < 0) { // discard; } - - //frag.forceFboRendering = true; - // todo: calculate full sample mask from nAaSamples instead of hardcoded 255. - if (!frag.forceFboRendering && (frag.color.a < 1.0 || sampleMask != 255)) { + + bool storeInAbuffer = false; + + if (frag.forceFboRendering) { + storeInAbuffer = false; + } else { + storeInAbuffer = frag.color.a < 1.0 || + sampleMask != 255 || + frag.blend != BLEND_MODE_NORMAL; + // todo: calculate full sample mask from nAaSamples instead of hardcoded 255. + } + + if (storeInAbuffer) { uint newHead = atomicCounterIncrement(atomicCounterBuffer); if (newHead >= #{rendererData.maxTotalFragments}) { discard; // ABuffer is full! diff --git a/shaders/abuffer/resolveabuffer.frag b/shaders/abuffer/resolveabuffer.frag index 38cb3269a5..a722c4f02d 100644 --- a/shaders/abuffer/resolveabuffer.frag +++ b/shaders/abuffer/resolveabuffer.frag @@ -113,7 +113,7 @@ void main() { //normalBlend(finalColor, color); } else if (blend == BLEND_MODE_ADDITIVE) { - accumulatedColor += (1 - accumulatedAlpha) * color.rgb; + accumulatedColor += (1 - accumulatedAlpha) * color.rgb * color.a; //additiveBlend(finalColor, color); } } From bc586234679e21e7679829b7158748706749561f Mon Sep 17 00:00:00 2001 From: Emil Axelsson Date: Thu, 25 Aug 2016 18:26:59 +0200 Subject: [PATCH 04/92] add render bins to improve rendering of transparent objects using framebuffer renderer --- include/openspace/rendering/renderable.h | 12 ++++++++++++ include/openspace/util/updatestructures.h | 2 ++ modules/base/rendering/renderabletrail.cpp | 1 + src/rendering/abufferrenderer.cpp | 8 +++++++- src/rendering/framebufferrenderer.cpp | 11 +++++++++-- src/rendering/renderable.cpp | 14 ++++++++++++++ src/scene/scenegraphnode.cpp | 9 ++++++++- 7 files changed, 53 insertions(+), 4 deletions(-) diff --git a/include/openspace/rendering/renderable.h b/include/openspace/rendering/renderable.h index 7d618b1f3a..50a8c4d16c 100644 --- a/include/openspace/rendering/renderable.h +++ b/include/openspace/rendering/renderable.h @@ -51,6 +51,13 @@ class PowerScaledCoordinate; class Renderable : public properties::PropertyOwner { public: + enum class RenderBin : int { + Background = 1, + Opaque = 2, + Transparent = 4, + Overlay = 8 + }; + static Renderable* createFromDictionary(const ghoul::Dictionary& dictionary); // constructors & destructor @@ -72,6 +79,10 @@ public: virtual void postRender(const RenderData& data); virtual void update(const UpdateData& data); + RenderBin renderBin() const; + void setRenderBin(RenderBin bin); + bool matchesRenderBinMask(int binMask); + bool isVisible() const; bool hasTimeInterval(); @@ -89,6 +100,7 @@ protected: properties::BoolProperty _enabled; private: + RenderBin _renderBin; PowerScaledScalar boundingSphere_; std::string _startTime; std::string _endTime; diff --git a/include/openspace/util/updatestructures.h b/include/openspace/util/updatestructures.h index 08ea000572..6de6df88e5 100644 --- a/include/openspace/util/updatestructures.h +++ b/include/openspace/util/updatestructures.h @@ -43,10 +43,12 @@ struct UpdateData { bool doPerformanceMeasurement; }; + struct RenderData { const Camera& camera; psc position; bool doPerformanceMeasurement; + int renderBinMask; }; struct RaycasterTask { diff --git a/modules/base/rendering/renderabletrail.cpp b/modules/base/rendering/renderabletrail.cpp index 265321f8ae..e6fa38c991 100644 --- a/modules/base/rendering/renderabletrail.cpp +++ b/modules/base/rendering/renderabletrail.cpp @@ -124,6 +124,7 @@ bool RenderableTrail::initialize() { "${MODULE_BASE}/shaders/ephemeris_vs.glsl", "${MODULE_BASE}/shaders/ephemeris_fs.glsl"); + setRenderBin(Renderable::RenderBin::Overlay); if (!_programObject) return false; diff --git a/src/rendering/abufferrenderer.cpp b/src/rendering/abufferrenderer.cpp index 234c2b205c..c38e3c9487 100644 --- a/src/rendering/abufferrenderer.cpp +++ b/src/rendering/abufferrenderer.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -260,7 +261,12 @@ void ABufferRenderer::render(float blackoutFactor, bool doPerformanceMeasurement glBindImageTexture(1, _fragmentTexture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32UI); // Render the scene to the fragment buffer. Collect renderer tasks (active raycasters) - RenderData data{ *_camera, psc(), doPerformanceMeasurements }; + int renderBinMask = static_cast(Renderable::RenderBin::Background) | + static_cast(Renderable::RenderBin::Opaque) | + static_cast(Renderable::RenderBin::Transparent) | + static_cast(Renderable::RenderBin::Overlay); + + RenderData data{ *_camera, psc(), doPerformanceMeasurements, renderBinMask }; RendererTasks tasks; _scene->render(data, tasks); diff --git a/src/rendering/framebufferrenderer.cpp b/src/rendering/framebufferrenderer.cpp index bd6b920987..af1c2c23c2 100644 --- a/src/rendering/framebufferrenderer.cpp +++ b/src/rendering/framebufferrenderer.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -329,7 +330,7 @@ void FramebufferRenderer::render(float blackoutFactor, bool doPerformanceMeasure glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - RenderData data = { *_camera, psc(), doPerformanceMeasurements }; + RenderData data = { *_camera, psc(), doPerformanceMeasurements, 0 }; RendererTasks tasks; // Capture standard fbo @@ -339,7 +340,13 @@ void FramebufferRenderer::render(float blackoutFactor, bool doPerformanceMeasure glBindFramebuffer(GL_FRAMEBUFFER, _mainFramebuffer); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // bind new fbo A with color and depth buffer. + data.renderBinMask = static_cast(Renderable::RenderBin::Background); + _scene->render(data, tasks); + data.renderBinMask = static_cast(Renderable::RenderBin::Opaque); + _scene->render(data, tasks); + data.renderBinMask = static_cast(Renderable::RenderBin::Transparent); + _scene->render(data, tasks); + data.renderBinMask = static_cast(Renderable::RenderBin::Overlay); _scene->render(data, tasks); for (const RaycasterTask& raycasterTask : tasks.raycasterTasks) { diff --git a/src/rendering/renderable.cpp b/src/rendering/renderable.cpp index 767920c5c1..65ec2f24ae 100644 --- a/src/rendering/renderable.cpp +++ b/src/rendering/renderable.cpp @@ -72,6 +72,7 @@ Renderable* Renderable::createFromDictionary(const ghoul::Dictionary& dictionary Renderable::Renderable() : _enabled("enabled", "Is Enabled", true) + , _renderBin(RenderBin::Opaque) , _startTime("") , _endTime("") , _targetBody("") @@ -83,6 +84,7 @@ Renderable::Renderable() Renderable::Renderable(const ghoul::Dictionary& dictionary) : _enabled("enabled", "Is Enabled", true) + , _renderBin(RenderBin::Opaque) , _startTime("") , _endTime("") , _targetBody("") @@ -148,6 +150,18 @@ void Renderable::setPscUniforms( program.setUniform("scaling", camera.scaling()); } +Renderable::RenderBin Renderable::renderBin() const { + return _renderBin; +} + +void Renderable::setRenderBin(RenderBin bin) { + _renderBin = bin; +} + +bool Renderable::matchesRenderBinMask(int binMask) { + return binMask & static_cast(renderBin()); +} + bool Renderable::isVisible() const { return _enabled; } diff --git a/src/scene/scenegraphnode.cpp b/src/scene/scenegraphnode.cpp index 2adc913240..d4ccb44110 100644 --- a/src/scene/scenegraphnode.cpp +++ b/src/scene/scenegraphnode.cpp @@ -248,7 +248,14 @@ void SceneGraphNode::render(const RenderData& data, RendererTasks& tasks) { RenderData newData = {data.camera, thisPosition, data.doPerformanceMeasurement}; _performanceRecord.renderTime = 0; - if (_renderableVisible && _renderable->isVisible() && _renderable->isReady() && _renderable->isEnabled()) { + + bool visible = _renderableVisible && + _renderable->isVisible() && + _renderable->isReady() && + _renderable->isEnabled() && + _renderable->matchesRenderBinMask(data.renderBinMask); + + if (visible) { if (data.doPerformanceMeasurement) { glFinish(); auto start = std::chrono::high_resolution_clock::now(); From b6be6da9748b9e9ca9d7cef6f6a50e6f21462ec9 Mon Sep 17 00:00:00 2001 From: Emil Axelsson Date: Thu, 25 Aug 2016 20:22:07 +0200 Subject: [PATCH 05/92] add support for additive blending in renderable plane --- data/scene/sun/sun.mod | 3 ++- modules/base/rendering/renderableplane.cpp | 31 +++++++++++++++++++++- modules/base/rendering/renderableplane.h | 6 +++++ modules/base/shaders/plane_fs.glsl | 6 +++++ 4 files changed, 44 insertions(+), 2 deletions(-) diff --git a/data/scene/sun/sun.mod b/data/scene/sun/sun.mod index 288335bb39..db9d83a9e8 100644 --- a/data/scene/sun/sun.mod +++ b/data/scene/sun/sun.mod @@ -50,7 +50,8 @@ return { Size = {1.3, 10.5}, Origin = "Center", Billboard = true, - Texture = "textures/sun-glare.png" + Texture = "textures/sun-glare.png", + BlendMode = "Additive" }, Ephemeris = { Type = "Spice", diff --git a/modules/base/rendering/renderableplane.cpp b/modules/base/rendering/renderableplane.cpp index b16652745d..d86a216269 100644 --- a/modules/base/rendering/renderableplane.cpp +++ b/modules/base/rendering/renderableplane.cpp @@ -60,6 +60,7 @@ RenderablePlane::RenderablePlane(const ghoul::Dictionary& dictionary) , _shader(nullptr) , _textureIsDirty(false) , _texture(nullptr) + , _blendMode(BlendMode::Normal) , _quad(0) , _vertexPositionBuffer(0) { @@ -67,7 +68,7 @@ RenderablePlane::RenderablePlane(const ghoul::Dictionary& dictionary) dictionary.getValue("Size", size); _size = size; - if (dictionary.hasKey("Name")){ + if (dictionary.hasKey("Name")) { dictionary.getValue("Name", _nodeName); } @@ -102,6 +103,13 @@ RenderablePlane::RenderablePlane(const ghoul::Dictionary& dictionary) } } + std::string blendMode; + if (dictionary.getValue("BlendMode", blendMode)) { + if (blendMode == "Additive") { + _blendMode = BlendMode::Additive; + setRenderBin(Renderable::RenderBin::Transparent); + } + } std::string texturePath = ""; bool success = dictionary.getValue("Texture", texturePath); @@ -213,9 +221,30 @@ void RenderablePlane::render(const RenderData& data) { _texture->bind(); _shader->setUniform("texture1", unit); + bool usingFramebufferRenderer = + OsEng.renderEngine().rendererImplementation() == RenderEngine::RendererImplementation::Framebuffer; + + bool usingABufferRenderer = + OsEng.renderEngine().rendererImplementation() == RenderEngine::RendererImplementation::ABuffer; + + if (usingABufferRenderer) { + _shader->setUniform("additiveBlending", _blendMode == BlendMode::Additive); + } + + bool additiveBlending = _blendMode == BlendMode::Additive && usingFramebufferRenderer; + if (additiveBlending) { + glDepthMask(false); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + } + glBindVertexArray(_quad); glDrawArrays(GL_TRIANGLES, 0, 6); + if (additiveBlending) { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDepthMask(true); + } + _shader->deactivate(); } diff --git a/modules/base/rendering/renderableplane.h b/modules/base/rendering/renderableplane.h index eaa5cf4445..fc4e8f795c 100644 --- a/modules/base/rendering/renderableplane.h +++ b/modules/base/rendering/renderableplane.h @@ -51,6 +51,11 @@ class RenderablePlane : public Renderable { }; public: + enum class BlendMode : int { + Normal = 0, + Additive + }; + RenderablePlane(const ghoul::Dictionary& dictionary); ~RenderablePlane(); @@ -79,6 +84,7 @@ private: std::unique_ptr _shader; bool _textureIsDirty; std::unique_ptr _texture; + BlendMode _blendMode; ghoul::filesystem::File* _textureFile; GLuint _quad; GLuint _vertexPositionBuffer; diff --git a/modules/base/shaders/plane_fs.glsl b/modules/base/shaders/plane_fs.glsl index 778763430e..1c4aeed1ee 100644 --- a/modules/base/shaders/plane_fs.glsl +++ b/modules/base/shaders/plane_fs.glsl @@ -24,6 +24,7 @@ uniform float time; uniform sampler2D texture1; +uniform bool additiveBlending; in vec2 vs_st; in vec4 vs_position; @@ -52,6 +53,11 @@ Fragment getFragment() { Fragment frag; frag.color = diffuse; frag.depth = depth; + + if (additiveBlending) { + frag.blend = BLEND_MODE_ADDITIVE; + } + return frag; } From 47583327ec168fb1538bf54c03c410b1ae593f33 Mon Sep 17 00:00:00 2001 From: Emil Axelsson Date: Fri, 26 Aug 2016 10:31:02 +0200 Subject: [PATCH 06/92] use additive blending for white planet markers to avoid z-fighting --- data/scene/atmosphereearth/atmosphereearth.mod | 3 ++- data/scene/earth/earth.mod | 3 ++- data/scene/newhorizons/jupiter/callisto/callisto.mod | 3 ++- data/scene/newhorizons/jupiter/europa/europa.mod | 3 ++- data/scene/newhorizons/jupiter/ganymede/ganymede.mod | 3 ++- data/scene/newhorizons/jupiter/io/io.mod | 3 ++- data/scene/newhorizons/jupiter/jupiter/jupiter.mod | 3 ++- data/scene/newhorizons/pluto/charon/charon.mod | 3 ++- data/scene/newhorizons/pluto/pluto/pluto.mod | 3 ++- data/scene/newhorizons/pluto/styx/styx.mod | 3 ++- data/scene/sun/sun.mod | 3 ++- 11 files changed, 22 insertions(+), 11 deletions(-) diff --git a/data/scene/atmosphereearth/atmosphereearth.mod b/data/scene/atmosphereearth/atmosphereearth.mod index 7ab2b2121e..166a0bdbad 100644 --- a/data/scene/atmosphereearth/atmosphereearth.mod +++ b/data/scene/atmosphereearth/atmosphereearth.mod @@ -129,7 +129,8 @@ return { Size = {3.0, 11.0}, Origin = "Center", Billboard = true, - Texture = "textures/marker.png" + Texture = "textures/marker.png", + BlendMode = "Additive" }, Ephemeris = { Type = "Static", diff --git a/data/scene/earth/earth.mod b/data/scene/earth/earth.mod index 3b23d70ee5..d62fd62f32 100644 --- a/data/scene/earth/earth.mod +++ b/data/scene/earth/earth.mod @@ -64,7 +64,8 @@ return { Size = {3.0, 11.0}, Origin = "Center", Billboard = true, - Texture = "textures/marker.png" + Texture = "textures/marker.png", + BlendMode = "Additive" }, Ephemeris = { Type = "Static", diff --git a/data/scene/newhorizons/jupiter/callisto/callisto.mod b/data/scene/newhorizons/jupiter/callisto/callisto.mod index 5bb6ed57f7..3fc6377bcc 100644 --- a/data/scene/newhorizons/jupiter/callisto/callisto.mod +++ b/data/scene/newhorizons/jupiter/callisto/callisto.mod @@ -60,7 +60,8 @@ return { Size = {1.0, 7.4}, Origin = "Center", Billboard = true, - Texture = "textures/Callisto-Text.png" + Texture = "textures/Callisto-Text.png", + BlendMode = "Additive" }, Ephemeris = { Type = "Static", diff --git a/data/scene/newhorizons/jupiter/europa/europa.mod b/data/scene/newhorizons/jupiter/europa/europa.mod index ff14b3448c..1c8878a6c5 100644 --- a/data/scene/newhorizons/jupiter/europa/europa.mod +++ b/data/scene/newhorizons/jupiter/europa/europa.mod @@ -60,7 +60,8 @@ return { Size = {1.0, 7.4}, Origin = "Center", Billboard = true, - Texture = "textures/Europa-Text.png" + Texture = "textures/Europa-Text.png", + BlendMode = "Additive" }, Ephemeris = { Type = "Static", diff --git a/data/scene/newhorizons/jupiter/ganymede/ganymede.mod b/data/scene/newhorizons/jupiter/ganymede/ganymede.mod index 5c92635c06..4fc4a6673c 100644 --- a/data/scene/newhorizons/jupiter/ganymede/ganymede.mod +++ b/data/scene/newhorizons/jupiter/ganymede/ganymede.mod @@ -60,7 +60,8 @@ return { Size = {1.0, 7.4}, Origin = "Center", Billboard = true, - Texture = "textures/Ganymede-Text.png" + Texture = "textures/Ganymede-Text.png", + BlendMode = "Additive" }, Ephemeris = { Type = "Static", diff --git a/data/scene/newhorizons/jupiter/io/io.mod b/data/scene/newhorizons/jupiter/io/io.mod index 75053e1904..60b42e1645 100644 --- a/data/scene/newhorizons/jupiter/io/io.mod +++ b/data/scene/newhorizons/jupiter/io/io.mod @@ -60,7 +60,8 @@ return { Size = {1.0, 7.4}, Origin = "Center", Billboard = true, - Texture = "textures/Io-Text.png" + Texture = "textures/Io-Text.png", + BlendMode = "Additive" }, Ephemeris = { Type = "Static", diff --git a/data/scene/newhorizons/jupiter/jupiter/jupiter.mod b/data/scene/newhorizons/jupiter/jupiter/jupiter.mod index 542a2b1eac..c85879b7e4 100644 --- a/data/scene/newhorizons/jupiter/jupiter/jupiter.mod +++ b/data/scene/newhorizons/jupiter/jupiter/jupiter.mod @@ -106,7 +106,8 @@ return { Size = {1.0, 7.5}, Origin = "Center", Billboard = true, - Texture = "textures/Jupiter-text.png" + Texture = "textures/Jupiter-text.png", + BlendMode = "Additive" }, Ephemeris = { Type = "Static", diff --git a/data/scene/newhorizons/pluto/charon/charon.mod b/data/scene/newhorizons/pluto/charon/charon.mod index 674cb55892..ac01096cdc 100644 --- a/data/scene/newhorizons/pluto/charon/charon.mod +++ b/data/scene/newhorizons/pluto/charon/charon.mod @@ -77,7 +77,8 @@ return { Size = {1.0, 6.3}, Origin = "Center", Billboard = true, - Texture = "textures/Charon-Text.png" + Texture = "textures/Charon-Text.png", + BlendMode = "Additive" }, Ephemeris = { Type = "Static", diff --git a/data/scene/newhorizons/pluto/pluto/pluto.mod b/data/scene/newhorizons/pluto/pluto/pluto.mod index e5447cc48e..a23974d47d 100644 --- a/data/scene/newhorizons/pluto/pluto/pluto.mod +++ b/data/scene/newhorizons/pluto/pluto/pluto.mod @@ -194,7 +194,8 @@ return { Size = {1.0, 6.3}, Origin = "Center", Billboard = true, - Texture = "textures/Pluto-Text.png" + Texture = "textures/Pluto-Text.png", + BlendMode = "Additive" }, Ephemeris = { Type = "Static", diff --git a/data/scene/newhorizons/pluto/styx/styx.mod b/data/scene/newhorizons/pluto/styx/styx.mod index 02d6ad7a30..f34abbc84e 100644 --- a/data/scene/newhorizons/pluto/styx/styx.mod +++ b/data/scene/newhorizons/pluto/styx/styx.mod @@ -49,7 +49,8 @@ return { Size = {1.0, 6.3}, Origin = "Center", Billboard = true, - Texture = "textures/Styx-Text.png" + Texture = "textures/Styx-Text.png", + BlendMode = "Additive" }, Ephemeris = { Type = "Static", diff --git a/data/scene/sun/sun.mod b/data/scene/sun/sun.mod index db9d83a9e8..17caf205be 100644 --- a/data/scene/sun/sun.mod +++ b/data/scene/sun/sun.mod @@ -71,7 +71,8 @@ return { Size = {3.0, 11.0}, Origin = "Center", Billboard = true, - Texture = "textures/marker.png" + Texture = "textures/marker.png", + BlendMode = "Additive" }, Ephemeris = { Type = "Static", From d7ea0f8eadb2fdd5daeb41cd3a62a8ceab107664 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Tue, 30 Aug 2016 01:26:43 +0200 Subject: [PATCH 07/92] Enable the use of a separate model transform in RenderableModel --- modules/base/rendering/renderablemodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/base/rendering/renderablemodel.cpp b/modules/base/rendering/renderablemodel.cpp index 376fe8cf81..f562c3427e 100644 --- a/modules/base/rendering/renderablemodel.cpp +++ b/modules/base/rendering/renderablemodel.cpp @@ -211,7 +211,7 @@ void RenderableModel::render(const RenderData& data) { glm::dmat4 modelTransform = glm::translate(glm::dmat4(1.0), data.modelTransform.translation) * // Translation glm::dmat4(data.modelTransform.rotation) * // Spice rotation - glm::dmat4(glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale))); + glm::dmat4(glm::scale(glm::dmat4(_modelTransform), glm::dvec3(data.modelTransform.scale))); debugModelRotation; // debug model rotation controlled from GUI glm::dmat4 modelViewTransform = data.camera.combinedViewMatrix() * modelTransform; From e4bc8385fb57b2a372ef1a146b2907242fecfae0 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Tue, 30 Aug 2016 01:27:11 +0200 Subject: [PATCH 08/92] Fix the StaticScale to correctly request only a single double --- modules/base/scale/staticscale.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/base/scale/staticscale.cpp b/modules/base/scale/staticscale.cpp index ff1573e61c..ed9fddd71c 100644 --- a/modules/base/scale/staticscale.cpp +++ b/modules/base/scale/staticscale.cpp @@ -33,9 +33,9 @@ namespace openspace { StaticScale::StaticScale(const ghoul::Dictionary& dictionary) : _scaleValue(1.0) { - const bool hasValue = dictionary.hasKeyAndValue(KeyValue); + bool hasValue = dictionary.hasKeyAndValue(KeyValue); if (hasValue) { - dictionary.getValue(KeyValue, _scaleValue); + _scaleValue = dictionary.value(KeyValue); } } From 2a244f42b75c9205cc9ba6cbc404728e113a5751 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Tue, 30 Aug 2016 01:30:54 +0200 Subject: [PATCH 09/92] Updated Rosetta kernels Removed old kernel torrent files Cleaned .gitignore --- .gitignore | 70 +---- data/scene/rosetta.scene | 3 +- data/scene/rosetta/rosetta/Rosetta.torrent | Bin 0 -> 18841 bytes .../rosetta/rosetta/RosettaKernels.torrent | Bin 23149 -> 0 bytes .../rosetta/RosettaKernels_New.torrent | Bin 12539 -> 0 bytes data/scene/rosetta/rosetta/rosetta.data | 3 +- data/scene/rosetta/rosetta/rosetta.mod | 250 +++++++++--------- 7 files changed, 148 insertions(+), 178 deletions(-) create mode 100644 data/scene/rosetta/rosetta/Rosetta.torrent delete mode 100644 data/scene/rosetta/rosetta/RosettaKernels.torrent delete mode 100644 data/scene/rosetta/rosetta/RosettaKernels_New.torrent diff --git a/.gitignore b/.gitignore index c413fb7c41..29d61f2358 100644 --- a/.gitignore +++ b/.gitignore @@ -37,60 +37,29 @@ shaders/ABuffer/constants.hglsl LuaScripting.txt Properties.txt log.html -gui/externaltimecontrol/CMakeLists.txt -gui/externaltimecontrol/main.cpp -gui/externaltimecontrol/mainwindow.cpp -gui/externaltimecontrol/mainwindow.h data/scene/rosetta/67P/obj/67P_rotated_5_130.obj data/spice/NewHorizonsKernels/ -data/spice/RosettaKernels/ data/scene/newhorizons/pluto/pluto/textures/ data/scene/newhorizons/pluto/pluto/utcEvents.txt -data/scene/rosetta/rosetta/obj/mainbodyros.obj -data/scene/rosetta/rosetta/obj/solarpanelleft.obj -data/scene/rosetta/rosetta/obj/solarpanelright.obj -data/scene/rosetta/rosetta/textures/defaultProj.png -data/scene/rosetta/rosetta/textures/glare_blue.png -data/scene/rosetta/rosetta/textures/gray.png -data/scene/rosetta/rosetta/textures/squarefov.png +data/scene/rosetta/rosetta/textures/* data/scene/saturn/textures/saturn.jpg data/scene/stars/colorbv.cmap data/scene/stars/speck/stars.speck data/scene/stars/textures/glare.png data/scene/stars/textures/halo.png -data/scene/sun/textures/marker.png -data/scene/sun/textures/sun-glare.png -data/scene/sun/textures/sun.jpg +data/scene/sun/textures/ data/scene/uranus/textures/uranus.jpg data/scene/venus/textures/venus.jpg data/scene/dawn/vestaprojection/VestaComet/VestaComet_5000.obj data/spice/DawnKernels/ data/scene/newhorizons/jupiter/jupiter/ProjectionsOfInterest/ -data/scene/rosetta/67P/textures/black.jpg -data/scene/rosetta/67P/textures/defaultProj.png -data/scene/rosetta/67P/textures/gray.jpg -data/scene/rosetta/67P/textures/gray.png -data/scene/rosetta/67P/textures/texmapflipped.jpg -data/scene/rosetta/67P/textures/white.jpg -data/scene/rosetta/67P/textures/white.png +data/scene/rosetta/67P/textures data/scene/newhorizons/jupiter/callisto/textures/callisto.jpg data/scene/dawn/ceres/textures/gray.png -data/scene/newhorizons/pluto/charon/textures/Charon-Text.png -data/scene/newhorizons/pluto/charon/textures/charon_highres.jpg -data/scene/newhorizons/pluto/charon/textures/charon_highres_annotated.jpg -data/scene/newhorizons/pluto/charon/textures/defaultProj.png -data/scene/dawn/dawn/obj/mainbodydawn.obj -data/scene/dawn/dawn/obj/solarpanelleft.obj -data/scene/dawn/dawn/obj/solarpanelright.obj -data/scene/dawn/dawn/textures/glare_blue.png -data/scene/dawn/dawn/textures/gray.png -data/scene/earth/textures/ToastMapOfEarth.jpg -data/scene/earth/textures/earth_bluemarble.jpg -data/scene/earth/textures/earth_bluemarble_height.jpg -data/scene/earth/textures/earth_night.jpg -data/scene/earth/textures/marker.png -data/scene/earth/textures/earth_clouds.jpg -data/scene/earth/textures/earth_reflectance.png +data/scene/newhorizons/pluto/charon/textures/ +data/scene/dawn/dawn/obj/ +data/scene/dawn/dawn/textures/ +data/scene/earth/textures/ data/scene/moon/textures/Moon16k.dds data/scene/newhorizons/jupiter/europa/textures/europa.jpg data/scene/newhorizons/jupiter/ganymede/textures/ganymede.jpg @@ -100,11 +69,8 @@ data/scene/mars/textures/mars.jpg data/scene/mercury/textures/mercury.jpg data/scene/milkyway/textures/DarkUniverse_mellinger_8k.jpg data/scene/neptune/textures/neptune.jpg -data/scene/newhorizons/newhorizons/models/Labels.obj -data/scene/newhorizons/newhorizons/models/NewHorizonsCleanModel.obj -data/scene/newhorizons/newhorizons/textures/NHTexture.jpg -data/scene/newhorizons/newhorizons/textures/goldfoilbump.tif -data/scene/newhorizons/newhorizons/textures/labels.png +data/scene/newhorizons/newhorizons/models/ +data/scene/newhorizons/newhorizons/textures/ data/scene/pluto/textures/ data/scene/pluto/textures/Shenk_180.jpg data/scene/pluto/textures/pluto_highres_180.jpg @@ -112,10 +78,7 @@ data/scene/newhorizons/pluto/pluto/assets/core_v9h_obs_getmets_v8_time_fix_nofrc data/scene/newhorizons/pluto/pluto/textures/3.jpg data/scene/newhorizons/pluto/pluto/textures/Pluto-Text.png data/scene/dawn/vestaprojection/VestaComet/VestaComet.mtl -data/scene/dawn/vestaprojection/textures/defaultProj_backup.png -data/scene/dawn/vestaprojection/textures/dummy.jpg -data/scene/dawn/vestaprojection/textures/glare.png -data/scene/dawn/vestaprojection/textures/projectMe.png +data/scene/dawn/vestaprojection/textures/ data/spice/MAR063.BSP data/spice/de430_1850-2150.bsp data/spice/jup260.bsp @@ -134,7 +97,6 @@ data/scene/stars-denver/speck/stars.speck data/scene/stars-denver/textures/halo.png data/scene/newhorizons/pluto/pluto/full_images/ data/scene/rosetta/67P/rosettaimages/ -data/spice/RosettaKernels_New/ data/scene/newhorizons/pluto/charon/utcEvents.txt data/scene/rosetta/67P/obj/67P_HD_2015-05-09.obj data/scene/rosetta/67P/obj/may9_map.jpg @@ -143,21 +105,15 @@ data/scene/newhorizons/pluto/charon/textures/cpdem-Mcolor2-MLorriCA-lr-5_ZMfs-cy data/scene/newhorizons/pluto/charon/textures/cpmap_cyl_HR_0e.jpg data/scene/volumetricmilkyway/milkyway/ ScriptLog.txt -data/scene/atmosphereearth/textures/ToastMapOfEarth.jpg -data/scene/atmosphereearth/textures/earth_bluemarble.jpg -data/scene/atmosphereearth/textures/earth_bluemarble_height.jpg -data/scene/atmosphereearth/textures/earth_clouds.jpg -data/scene/atmosphereearth/textures/earth_night.jpg -data/scene/atmosphereearth/textures/earth_reflectance.png -data/scene/atmosphereearth/textures/marker.png +data/scene/atmosphereearth/textures/ data/scene/juno/juno/textures data/scene/juno/juno/spice data/scene/juno/juno/Juno.mtl data/scene/juno/juno/Juno.obj KeyboardMapping.txt saturn_rings.png -data/scene/debugglobe/textures/earth_clouds.jpg -data/scene/debugglobe/textures/earth_reflectance.png +data/scene/debugglobe/textures/ data/scene/rosetta/rosetta/obj/Rosetta.obj data/scene/rosetta/rosetta/rosetta/ data/scene/rosetta/rosetta/textures/ +data/spice/Rosetta/ diff --git a/data/scene/rosetta.scene b/data/scene/rosetta.scene index 4701468832..32a635067b 100644 --- a/data/scene/rosetta.scene +++ b/data/scene/rosetta.scene @@ -10,6 +10,7 @@ function preInitialization() openspace.spice.loadKernel("${SPICE}/pck00010.tpc") openspace.time.setTime("2014-08-15T03:05:18.101") + -- openspace.time.setTime("2016-08-20T03:05:18.101") -- openspace.time.setTime("2014-11-17T03:05:18.101") -- openspace.time.setTime("2015-07-29T06:02:10.000") -- openspace.time.setTime("2014 AUG 21 18:00:00") @@ -50,7 +51,7 @@ return { "venus", "earth", "mars", - "jupiter", + "jupiter/jupiter", "saturn", "uranus", "neptune", diff --git a/data/scene/rosetta/rosetta/Rosetta.torrent b/data/scene/rosetta/rosetta/Rosetta.torrent new file mode 100644 index 0000000000000000000000000000000000000000..c714826b8c0fbc05a193aad66d0f959c1db1b7c0 GIT binary patch literal 18841 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 diff --git a/data/scene/rosetta/rosetta/RosettaKernels_New.torrent b/data/scene/rosetta/rosetta/RosettaKernels_New.torrent deleted file mode 100644 index cdb32f8b5dd8dfc9181f2175e5ccf6ed6c52c4a2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12539 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 SZV7jBbGCz9{&|-H{(k_RlhP0X diff --git a/data/scene/rosetta/rosetta/rosetta.data b/data/scene/rosetta/rosetta/rosetta.data index f49beed4ff..fbef76bd99 100644 --- a/data/scene/rosetta/rosetta/rosetta.data +++ b/data/scene/rosetta/rosetta/rosetta.data @@ -4,7 +4,6 @@ return { { Identifier = "rosetta_textures", Destination = "textures", Version = 2 } }, TorrentFiles = { - { File = "RosettaKernels.torrent", Destination = "${SPICE}" }, - { File = "RosettaKernels_New.torrent", Destination = "${SPICE}" } + { File = "Rosetta.torrent", Destination = "${SPICE}" }, } } \ No newline at end of file diff --git a/data/scene/rosetta/rosetta/rosetta.mod b/data/scene/rosetta/rosetta/rosetta.mod index 0796af4c13..19339a6612 100644 --- a/data/scene/rosetta/rosetta/rosetta.mod +++ b/data/scene/rosetta/rosetta/rosetta.mod @@ -1,58 +1,61 @@ RosettaKernels = { - --needed - "${OPENSPACE_DATA}/spice/de430_1850-2150.bsp", - -- SPK - --long term orbits loaded first - -- '${OPENSPACE_DATA}/spice/RosettaKernels/SPK/LORL_DL_006_01____H__00156.BSP', - -- '${OPENSPACE_DATA}/spice/RosettaKernels/SPK/RORL_DL_006_01____H__00156.BSP', - -- '${OPENSPACE_DATA}/spice/RosettaKernels/SPK/CORL_DL_006_01____H__00156.BSP', + "${OPENSPACE_DATA}/spice/Rosetta/SPK/CORB_DV_243_01___T19_00325.BSP", + "${OPENSPACE_DATA}/spice/Rosetta/SPK/CORB_DV_223_01___T19_00302.BSP", + "${OPENSPACE_DATA}/spice/Rosetta/SPK/CORB_DV_145_01___T19_00216.BSP", - --Jan 2014 - May 2015 (version match with 00162 ck files) - -- "${OPENSPACE_DATA}/spice/RosettaKernels/SPK/CORB_DV_097_01_______00162.BSP", - -- "${OPENSPACE_DATA}/spice/RosettaKernels/SPK/RORB_DV_097_01_______00162.BSP", - -- "${OPENSPACE_DATA}/spice/RosettaKernels/SPK/LORB_DV_097_01_______00162.BSP", + "${OPENSPACE_DATA}/spice/Rosetta/SPK/LORB_DV_236_01___T19_00318.BSP", + "${OPENSPACE_DATA}/spice/Rosetta/SPK/LORB_DV_223_01___T19_00302.BSP", + "${OPENSPACE_DATA}/spice/Rosetta/SPK/LORB_DV_145_01___T19_00216.BSP", + + "${OPENSPACE_DATA}/spice/Rosetta/SPK/RORB_DV_243_01___T19_00325.BSP", + "${OPENSPACE_DATA}/spice/Rosetta/SPK/RORB_DV_223_01___T19_00302.BSP", + "${OPENSPACE_DATA}/spice/Rosetta/SPK/RORB_DV_145_01___T19_00216.BSP", - --IK - "${OPENSPACE_DATA}/spice/RosettaKernels_New/IK/ROS_NAVCAM_V01.TI", - "${OPENSPACE_DATA}/spice/RosettaKernels/IK/ROS_NAVCAM_V00-20130102.TI", + "${OPENSPACE_DATA}/spice/Rosetta/CK/ATNR_P040302093352_00127.BC", - --SCLK - -- "${OPENSPACE_DATA}/spice/RosettaKernels/SCLK/ROS_150227_STEP.TSC", + "${OPENSPACE_DATA}/spice/Rosetta/SPK/ROS_STRUCT_V5.BSP", - -- FK - -- "${OPENSPACE_DATA}/spice/RosettaKernels/FK/ROS_CHURYUMOV_V01.TF", - -- "${OPENSPACE_DATA}/spice/RosettaKernels/FK/ROS_V24.TF", + "${OPENSPACE_DATA}/spice/Rosetta/IK/ROS_NAVCAM_V01.TI", + + "${OPENSPACE_DATA}/spice/Rosetta/SCLK/ROS_160718_STEP.TSC", + "${OPENSPACE_DATA}/spice/Rosetta/SCLK/ros_triv.tsc", + + "${OPENSPACE_DATA}/spice/Rosetta/FK/ROS_CHURYUMOV_V01.TF", + "${OPENSPACE_DATA}/spice/Rosetta/FK/ROS_V26.TF", -- CK - -- '${OPENSPACE_DATA}/spice/RosettaKernels/CK/RATT_DV_097_01_01____00162.BC', - -- "${OPENSPACE_DATA}/spice/RosettaKernels/CK/CATT_DV_097_01_______00162.BC", + -- Rosetta attitude + "${OPENSPACE_DATA}/spice/Rosetta/CK/RATT_DV_243_01_01____00325.BC", + "${OPENSPACE_DATA}/spice/Rosetta/CK/RATT_DV_223_01_01____00302.BC", + "${OPENSPACE_DATA}/spice/Rosetta/CK/RATT_DV_145_01_01____00216.BC", - --SCLK - -- "${OPENSPACE_DATA}/spice/RosettaKernels/SCLK/ROS_150227_STEP.TSC", - "${OPENSPACE_DATA}/spice/RosettaKernels_New/SCLK/ROS_160425_STEP.TSC", + -- Comet attitude + "${OPENSPACE_DATA}/spice/Rosetta/CK/CATT_DV_243_01_______00325.BC", + "${OPENSPACE_DATA}/spice/Rosetta/CK/CATT_DV_223_01_______00302.BC", + "${OPENSPACE_DATA}/spice/Rosetta/CK/CATT_DV_145_01_______00216.BC", - -- FK + -- High gain antenna + "${OPENSPACE_DATA}/spice/Rosetta/CK/ROS_HGA_2016_V0035.BC", + "${OPENSPACE_DATA}/spice/Rosetta/CK/ROS_HGA_2015_V0053.BC", + "${OPENSPACE_DATA}/spice/Rosetta/CK/ROS_HGA_2014_V0044.BC", - "${OPENSPACE_DATA}/spice/RosettaKernels_New/FK/ROS_CHURYUMOV_V01.TF", - "${OPENSPACE_DATA}/spice/RosettaKernels_New/FK/ROS_V26.TF", - -- "${OPENSPACE_DATA}/spice/RosettaKernels/FK/ROS_V24.TF", - -- CK - "${OPENSPACE_DATA}/spice/RosettaKernels_New/CK/RATT_DV_211_01_01____00288.BC", - "${OPENSPACE_DATA}/spice/RosettaKernels_New/CK/CATT_DV_211_01_______00288.BC", - '${OPENSPACE_DATA}/spice/RosettaKernels/CK/RATT_DV_097_01_01____00162.BC', - "${OPENSPACE_DATA}/spice/RosettaKernels/CK/CATT_DV_097_01_______00162.BC", - - -- PCK - "${OPENSPACE_DATA}/spice/RosettaKernels_New/PCK/ROS_CGS_RSOC_V03.TPC", - -- "${OPENSPACE_DATA}/spice/RosettaKernels/PCK/ROS_CGS_RSOC_V03.TPC", + -- Solar arrays + "${OPENSPACE_DATA}/spice/Rosetta/CK/ROS_SA_2016_V0034.BC", + "${OPENSPACE_DATA}/spice/Rosetta/CK/ROS_SA_2015_V0042.BC", + "${OPENSPACE_DATA}/spice/Rosetta/CK/ROS_SA_2014_V0047.BC", - - "${OPENSPACE_DATA}/spice/RosettaKernels_New/CK/ROS_SA_2014_V0047.BC", - "${OPENSPACE_DATA}/spice/RosettaKernels_New/CK/ROS_SA_2015_V0042.BC", - "${OPENSPACE_DATA}/spice/RosettaKernels_New/CK/ROS_SA_2016_V0019.BC", + "${OPENSPACE_DATA}/spice/Rosetta/PCK/ROS_CGS_RSOC_V03.TPC", } +RotationMatrix = { + 0, 1, 0, + 0, 0, 1, + 1, 0, 0 +} + + + return { { Name = "Rosetta", @@ -64,7 +67,7 @@ return { Reference = "GALACTIC", Observer = "SUN", Kernels = RosettaKernels - }, + }, Rotation = { Type = "SpiceRotation", SourceFrame = "ROS_SPACECRAFT", @@ -73,8 +76,19 @@ return { } }, { - Name = "Rosetta_black_foil", + Name = "RosettaModel", Parent = "Rosetta", + Transform = { + Scale = { + Type = "StaticScale", + -- The scale of the model is in cm; OpenSpace is in m + Scale = 0.01 + } + } + }, + { + Name = "Rosetta_black_foil", + Parent = "RosettaModel", Renderable = { Type = "RenderableModel", Body = "ROSETTA", @@ -85,12 +99,13 @@ return { Textures = { Type = "simple", Color = "textures/foil_silver_ramp.png" - } + }, + Rotation = { ModelTransform = RotationMatrix } } }, { Name = "Rosetta_black_parts", - Parent = "Rosetta", + Parent = "RosettaModel", Renderable = { Type = "RenderableModel", Body = "ROSETTA", @@ -101,12 +116,13 @@ return { Textures = { Type = "simple", Color = "textures/foil_silver_ramp.png" - } + }, + Rotation = { ModelTransform = RotationMatrix } } }, { Name = "Rosetta_dish", - Parent = "Rosetta", + Parent = "RosettaModel", Renderable = { Type = "RenderableModel", Body = "ROSETTA", @@ -117,12 +133,21 @@ return { Textures = { Type = "simple", Color = "textures/dish_AO.png" + }, + Rotation = { ModelTransform = RotationMatrix } + + }, + Transform = { + Rotation = { + Type = "SpiceRotation", + SourceFrame = "-226071", -- ROS_HGA + DestinationFrame = "ROS_SPACECRAFT", } } }, { Name = "Rosetta_parts", - Parent = "Rosetta", + Parent = "RosettaModel", Renderable = { Type = "RenderableModel", Body = "ROSETTA", @@ -133,12 +158,14 @@ return { Textures = { Type = "simple", Color = "textures/parts2_AO.png" - } + }, + Rotation = { ModelTransform = RotationMatrix } + } }, { Name = "Rosetta_silver_foil", - Parent = "Rosetta", + Parent = "RosettaModel", Renderable = { Type = "RenderableModel", Body = "ROSETTA", @@ -149,12 +176,14 @@ return { Textures = { Type = "simple", Color = "textures/foil_silver_ramp.png" - } + }, + Rotation = { ModelTransform = RotationMatrix } + } }, { Name = "Rosetta_vents", - Parent = "Rosetta", + Parent = "RosettaModel", Renderable = { Type = "RenderableModel", Body = "ROSETTA", @@ -165,12 +194,14 @@ return { Textures = { Type = "simple", Color = "textures/tex_01.png" - } + }, + Rotation = { ModelTransform = RotationMatrix } + } }, { Name = "Rosetta_wing_a", - Parent = "Rosetta", + Parent = "RosettaModel", Renderable = { Type = "RenderableModel", Body = "ROSETTA", @@ -181,12 +212,21 @@ return { Textures = { Type = "simple", Color = "textures/tex_01.png" + }, + Rotation = { ModelTransform = RotationMatrix } + + }, + Transform = { + Rotation = { + Type = "SpiceRotation", + SourceFrame = "-226015", -- ROS_SA + DestinationFrame = "ROS_SPACECRAFT", } } }, { Name = "Rosetta_wing_b", - Parent = "Rosetta", + Parent = "RosettaModel", Renderable = { Type = "RenderableModel", Body = "ROSETTA", @@ -197,12 +237,21 @@ return { Textures = { Type = "simple", Color = "textures/tex_01.png" + }, + Rotation = { ModelTransform = RotationMatrix } + + }, + Transform = { + Rotation = { + Type = "SpiceRotation", + SourceFrame = "-226025", -- ROS_SA + DestinationFrame = "ROS_SPACECRAFT", } } }, { Name = "Rosetta_yellow_foil", - Parent = "Rosetta", + Parent = "RosettaModel", Renderable = { Type = "RenderableModel", Body = "ROSETTA", @@ -213,12 +262,14 @@ return { Textures = { Type = "simple", Color = "textures/foil_gold_ramp.png" - } + }, + Rotation = { ModelTransform = RotationMatrix } + } }, { Name = "Philae", - Parent = "Rosetta" + Parent = "RosettaModel" -- This should need a transform, but currently the model is intrinsically -- translated }, @@ -235,7 +286,9 @@ return { Textures = { Type = "simple", Color = "textures/foil_silver_ramp.png" - } + }, + Rotation = { ModelTransform = RotationMatrix } + } }, { @@ -251,7 +304,9 @@ return { Textures = { Type = "simple", Color = "textures/parts2_AO.png" - } + }, + Rotation = { ModelTransform = RotationMatrix } + } }, { @@ -267,7 +322,9 @@ return { Textures = { Type = "simple", Color = "textures/foil_silver_ramp.png" - } + }, + Rotation = { ModelTransform = RotationMatrix } + } }, { @@ -283,55 +340,12 @@ return { Textures = { Type = "simple", Color = "textures/tex_01.png" - } + }, + Rotation = { ModelTransform = RotationMatrix } + } }, - --[[ -- Rosetta Trail Module - { - Name = "RosettaTrail", - Parent = "67P", - Renderable = { - Type = "RenderableTrail", - Body = "ROSETTA", - Frame = "GALACTIC", - Observer = "SUN", - -- 3 Dummy values for compilation: - TropicalOrbitPeriod = 10000.0, - EarthOrbitRatio = 2, - DayLength = 50, - -- End of Dummy values - RGB = { 0.7, 0.7, 0.4 }, - Textures = { - Type = "simple", - Color = "textures/glare.png" - }, - }, - GuiName = "RosettaTrail" - }, --]] - -- Comet Dance trail - --[[{ - Name = "RosettaCometTrail", - Parent = "67P", - Renderable = { - Type = "RenderableTrail", - Body = "ROSETTA", - Frame = "GALACTIC", - Observer = "CHURYUMOV-GERASIMENKO", - TropicalOrbitPeriod = 20000.0, - EarthOrbitRatio = 2, - DayLength = 25, - RGB = { 0.9, 0.2, 0.9 }, - Textures = { - Type = "simple", - Color = "textures/glare.png" - }, - StartTime = "2014 AUG 01 12:00:00", - EndTime = "2016 MAY 26 12:00:00" - }, - GuiName = "RosettaCometTrail" - }, - ]] - { + { Name = "RosettaCometTrail", Parent = "67PBarycenter", Renderable = { @@ -341,7 +355,7 @@ return { Frame = "GALACTIC", Observer = "CHURYUMOV-GERASIMENKO", -- Optional rendering properties - LineColor = { 0.9, 0.2, 0.9 }, + LineColor = { 0.288, 0.375, 0.934 }, PointColor = { 0.9, 0.2, 0.9 }, LineFade = 0.0, -- [0,1] RenderPart = 0.5, -- [0,1] @@ -351,23 +365,23 @@ return { -- Time interval TimeRange = { Start = "2014 AUG 01 12:00:00", - End = "2016 MAY 26 12:00:00" + End = "2016 SEP 30 12:00:00" }, SampleDeltaTime = 3600, -- Seconds between each point - SubSamples = 3, + SubSamples = 0, }, GuiName = "/Solar/RosettaCometTrail" }, { Name = "NAVCAM", Parent = "Rosetta", - -- Transform = { - -- Rotation = { - -- Type = "SpiceRotation", - -- SourceFrame = "NAVCAM", - -- DestinationFrame = "ROS_SPACECRAFT", - -- }, - -- }, + Transform = { + Rotation = { + Type = "SpiceRotation", + SourceFrame = "NAVCAM", + DestinationFrame = "ROS_SPACECRAFT", + }, + }, GuiName = "/Solar/Rosetta_navcam" }, { From c06b7bce11728186e6ccb6921ae8fbaacb4bfec1 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Tue, 30 Aug 2016 10:48:12 +0200 Subject: [PATCH 10/92] Adding Philae trail --- data/scene/rosetta.scene | 4 +- data/scene/rosetta/67P/67P.mod | 22 ------ data/scene/rosetta/rosetta/rosetta.mod | 95 +++++++++++++++++--------- 3 files changed, 64 insertions(+), 57 deletions(-) diff --git a/data/scene/rosetta.scene b/data/scene/rosetta.scene index 32a635067b..0aa3c75884 100644 --- a/data/scene/rosetta.scene +++ b/data/scene/rosetta.scene @@ -9,9 +9,9 @@ function preInitialization() openspace.spice.loadKernel("${SPICE}/naif0011.tls") openspace.spice.loadKernel("${SPICE}/pck00010.tpc") - openspace.time.setTime("2014-08-15T03:05:18.101") + -- openspace.time.setTime("2014-08-15T03:05:18.101") -- openspace.time.setTime("2016-08-20T03:05:18.101") - -- openspace.time.setTime("2014-11-17T03:05:18.101") + openspace.time.setTime("2014-11-12T09:00:18.101") -- openspace.time.setTime("2015-07-29T06:02:10.000") -- openspace.time.setTime("2014 AUG 21 18:00:00") -- openspace.time.setTime("2015 SEP 10 19:39:00") diff --git a/data/scene/rosetta/67P/67P.mod b/data/scene/rosetta/67P/67P.mod index 27e25f8959..9c14de2e59 100644 --- a/data/scene/rosetta/67P/67P.mod +++ b/data/scene/rosetta/67P/67P.mod @@ -9,28 +9,6 @@ return { Body = "CHURYUMOV-GERASIMENKO", Reference = "GALACTIC", Observer = "SUN", - Kernels = { - --needed - "${OPENSPACE_DATA}/spice/de430_1850-2150.bsp", - -- SPK - --long term orbits loaded first - '${OPENSPACE_DATA}/spice/RosettaKernels_New/SPK/LORL_DL_009_02____P__00268.BSP', - '${OPENSPACE_DATA}/spice/RosettaKernels_New/SPK/RORL_DL_009_02____P__00268.BSP', - '${OPENSPACE_DATA}/spice/RosettaKernels_New/SPK/CORL_DL_009_02____P__00268.BSP', - - '${OPENSPACE_DATA}/spice/RosettaKernels/SPK/LORL_DL_006_01____H__00156.BSP', - '${OPENSPACE_DATA}/spice/RosettaKernels/SPK/RORL_DL_006_01____H__00156.BSP', - '${OPENSPACE_DATA}/spice/RosettaKernels/SPK/CORL_DL_006_01____H__00156.BSP', - - --Jan 2014 - May 2015 (version match with 00162 ck files) - "${OPENSPACE_DATA}/spice/RosettaKernels/SPK/CORB_DV_097_01_______00162.BSP", - "${OPENSPACE_DATA}/spice/RosettaKernels/SPK/RORB_DV_097_01_______00162.BSP", - "${OPENSPACE_DATA}/spice/RosettaKernels/SPK/LORB_DV_097_01_______00162.BSP", - - "${OPENSPACE_DATA}/spice/RosettaKernels_New/SPK/CORB_DV_211_01_______00288.BSP", - "${OPENSPACE_DATA}/spice/RosettaKernels_New/SPK/RORB_DV_211_01_______00288.BSP", - "${OPENSPACE_DATA}/spice/RosettaKernels_New/SPK/LORB_DV_211_01_______00288.BSP", - } }, }, GuiName = "/Solar/67PBarycenter", diff --git a/data/scene/rosetta/rosetta/rosetta.mod b/data/scene/rosetta/rosetta/rosetta.mod index 19339a6612..fd489a5f23 100644 --- a/data/scene/rosetta/rosetta/rosetta.mod +++ b/data/scene/rosetta/rosetta/rosetta.mod @@ -1,4 +1,7 @@ RosettaKernels = { + "${OPENSPACE_DATA}/spice/Rosetta/SCLK/ROS_160718_STEP.TSC", + "${OPENSPACE_DATA}/spice/Rosetta/SCLK/ros_triv.tsc", + "${OPENSPACE_DATA}/spice/Rosetta/SPK/CORB_DV_243_01___T19_00325.BSP", "${OPENSPACE_DATA}/spice/Rosetta/SPK/CORB_DV_223_01___T19_00302.BSP", "${OPENSPACE_DATA}/spice/Rosetta/SPK/CORB_DV_145_01___T19_00216.BSP", @@ -17,9 +20,6 @@ RosettaKernels = { "${OPENSPACE_DATA}/spice/Rosetta/IK/ROS_NAVCAM_V01.TI", - "${OPENSPACE_DATA}/spice/Rosetta/SCLK/ROS_160718_STEP.TSC", - "${OPENSPACE_DATA}/spice/Rosetta/SCLK/ros_triv.tsc", - "${OPENSPACE_DATA}/spice/Rosetta/FK/ROS_CHURYUMOV_V01.TF", "${OPENSPACE_DATA}/spice/Rosetta/FK/ROS_V26.TF", @@ -137,13 +137,13 @@ return { Rotation = { ModelTransform = RotationMatrix } }, - Transform = { - Rotation = { - Type = "SpiceRotation", - SourceFrame = "-226071", -- ROS_HGA - DestinationFrame = "ROS_SPACECRAFT", - } - } + -- Transform = { + -- Rotation = { + -- Type = "SpiceRotation", + -- SourceFrame = "-226071", -- ROS_HGA + -- DestinationFrame = "ROS_SPACECRAFT", + -- } + -- } }, { Name = "Rosetta_parts", @@ -216,13 +216,13 @@ return { Rotation = { ModelTransform = RotationMatrix } }, - Transform = { - Rotation = { - Type = "SpiceRotation", - SourceFrame = "-226015", -- ROS_SA - DestinationFrame = "ROS_SPACECRAFT", - } - } + -- Transform = { + -- Rotation = { + -- Type = "SpiceRotation", + -- SourceFrame = "-226015", -- ROS_SA + -- DestinationFrame = "ROS_SPACECRAFT", + -- } + -- } }, { Name = "Rosetta_wing_b", @@ -241,13 +241,13 @@ return { Rotation = { ModelTransform = RotationMatrix } }, - Transform = { - Rotation = { - Type = "SpiceRotation", - SourceFrame = "-226025", -- ROS_SA - DestinationFrame = "ROS_SPACECRAFT", - } - } + -- Transform = { + -- Rotation = { + -- Type = "SpiceRotation", + -- SourceFrame = "-226025", -- ROS_SA + -- DestinationFrame = "ROS_SPACECRAFT", + -- } + -- } }, { Name = "Rosetta_yellow_foil", @@ -269,9 +269,18 @@ return { }, { Name = "Philae", - Parent = "RosettaModel" + Parent = "RosettaModel", -- This should need a transform, but currently the model is intrinsically -- translated + -- Transform = { + -- Translation = { + -- Type = "SpiceEphemeris", + -- Body = "PHILAE", + -- Reference = "GALACTIC", + -- Observer = "ROSETTA", + -- Kernels = RosettaKernels + -- } + -- } }, { Name = "Philae_foil", @@ -368,20 +377,40 @@ return { End = "2016 SEP 30 12:00:00" }, SampleDeltaTime = 3600, -- Seconds between each point - SubSamples = 0, + SubSamples = 3, }, GuiName = "/Solar/RosettaCometTrail" }, + { + Name = "PhilaeTrail", + Parent = "67PBarycenter", + Renderable = { + Type = "RenderableTrailNew", + -- Spice + Body = "PHILAE", + Frame = "GALACTIC", + Observer = "CHURYUMOV-GERASIMENKO", + -- Optional rendering properties + LineColor = { 1.0, 1.0, 1.0 }, + PointColor = { 0.9, 0.2, 0.9 }, + LineFade = 0.0, -- [0,1] + RenderPart = 0.5, -- [0,1] + LineWidth = 2, + ShowTimeStamps = false, + RenderFullTrail = false, + -- Time interval + TimeRange = { + Start = "2014 NOV 12 08:35:00", + End = "2014 NOV 12 17:00:00" + }, + SampleDeltaTime = 2, -- Seconds between each point + SubSamples = 0, + }, + GuiName = "/Solar/RosettaCometTrail" + }, { Name = "NAVCAM", Parent = "Rosetta", - Transform = { - Rotation = { - Type = "SpiceRotation", - SourceFrame = "NAVCAM", - DestinationFrame = "ROS_SPACECRAFT", - }, - }, GuiName = "/Solar/Rosetta_navcam" }, { From 705f7b43aa8e66c5fe81c4b0912920d20e4a7952 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Tue, 30 Aug 2016 10:48:26 +0200 Subject: [PATCH 11/92] Make SpiceEphemeris check for the kernel existence before trying to load --- modules/base/ephemeris/spiceephemeris.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/modules/base/ephemeris/spiceephemeris.cpp b/modules/base/ephemeris/spiceephemeris.cpp index 36c81ac26a..85df8a21c9 100644 --- a/modules/base/ephemeris/spiceephemeris.cpp +++ b/modules/base/ephemeris/spiceephemeris.cpp @@ -27,6 +27,8 @@ #include #include +#include + namespace { const std::string _loggerCat = "SpiceEphemeris"; //const std::string keyGhosting = "EphmerisGhosting"; @@ -59,8 +61,15 @@ SpiceEphemeris::SpiceEphemeris(const ghoul::Dictionary& dictionary) for (size_t i = 1; i <= kernels.size(); ++i) { std::string kernel; bool success = kernels.getValue(std::to_string(i), kernel); - if (!success) + if (!success) { LERROR("'" << KeyKernels << "' has to be an array-style table"); + break; + } + + if (!FileSys.fileExists(kernel)) { + LERROR("Kernel '" << kernel << "' does not exist"); + continue; + } try { SpiceManager::ref().loadKernel(kernel); From 453c583fb137ee0e580626aa69e587e0e4d9c819 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Tue, 30 Aug 2016 10:48:37 +0200 Subject: [PATCH 12/92] Always render the date even if showInfo is false --- src/rendering/renderengine.cpp | 544 ++++++++++++++++----------------- 1 file changed, 272 insertions(+), 272 deletions(-) diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index 2991099afd..26f4f2efa7 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -420,9 +420,7 @@ void RenderEngine::render(const glm::mat4& projectionMatrix, const glm::mat4& vi // Print some useful information on the master viewport if (OsEng.isMaster() && OsEng.windowWrapper().isSimpleRendering()) { - if (_showInfo) { - renderInformation(); - } + renderInformation(); } for (auto screenSpaceRenderable : _screenSpaceRenderables) { @@ -1284,7 +1282,7 @@ void RenderEngine::renderInformation() { using Font = ghoul::fontrendering::Font; using ghoul::fontrendering::RenderFont; - if (_showInfo && _fontDate && _fontInfo) { + if (_fontDate) { glm::vec2 penPosition = glm::vec2( 10.f, OsEng.windowWrapper().viewportPixelCoordinates().w @@ -1297,298 +1295,300 @@ void RenderEngine::renderInformation() { Time::ref().currentTimeUTC().c_str() ); - RenderFontCr(*_fontInfo, - penPosition, - "Simulation increment (s): %.0f", - Time::ref().deltaTime() + if (_showInfo && _fontInfo) { + RenderFontCr(*_fontInfo, + penPosition, + "Simulation increment (s): %.0f", + Time::ref().deltaTime() ); - switch (_frametimeType) { - case FrametimeType::DtTimeAvg: - RenderFontCr(*_fontInfo, - penPosition, - "Avg. Frametime: %.5f", - OsEng.windowWrapper().averageDeltaTime() - ); - break; - case FrametimeType::FPS: - RenderFontCr(*_fontInfo, - penPosition, - "FPS: %3.2f", - 1.0 / OsEng.windowWrapper().deltaTime() - ); - break; - case FrametimeType::FPSAvg: - RenderFontCr(*_fontInfo, - penPosition, - "Avg. FPS: %3.2f", - 1.0 / OsEng.windowWrapper().averageDeltaTime() - ); - break; - default: - RenderFontCr(*_fontInfo, - penPosition, - "Avg. Frametime: %.5f", - OsEng.windowWrapper().averageDeltaTime() - ); - break; - } + switch (_frametimeType) { + case FrametimeType::DtTimeAvg: + RenderFontCr(*_fontInfo, + penPosition, + "Avg. Frametime: %.5f", + OsEng.windowWrapper().averageDeltaTime() + ); + break; + case FrametimeType::FPS: + RenderFontCr(*_fontInfo, + penPosition, + "FPS: %3.2f", + 1.0 / OsEng.windowWrapper().deltaTime() + ); + break; + case FrametimeType::FPSAvg: + RenderFontCr(*_fontInfo, + penPosition, + "Avg. FPS: %3.2f", + 1.0 / OsEng.windowWrapper().averageDeltaTime() + ); + break; + default: + RenderFontCr(*_fontInfo, + penPosition, + "Avg. Frametime: %.5f", + OsEng.windowWrapper().averageDeltaTime() + ); + break; + } #ifdef OPENSPACE_MODULE_NEWHORIZONS_ENABLED - bool hasNewHorizons = scene()->sceneGraphNode("NewHorizons"); - double currentTime = Time::ref().currentTime(); + bool hasNewHorizons = scene()->sceneGraphNode("NewHorizons"); + double currentTime = Time::ref().currentTime(); - if (MissionManager::ref().hasCurrentMission()) { + if (MissionManager::ref().hasCurrentMission()) { - const Mission& mission = MissionManager::ref().currentMission(); + const Mission& mission = MissionManager::ref().currentMission(); - if (mission.phases().size() > 0) { + if (mission.phases().size() > 0) { - static const glm::vec4 nextMissionColor(0.7, 0.3, 0.3, 1); - //static const glm::vec4 missionProgressColor(0.4, 1.0, 1.0, 1); - static const glm::vec4 currentMissionColor(0.0, 0.5, 0.5, 1); - static const glm::vec4 missionProgressColor = currentMissionColor;// (0.4, 1.0, 1.0, 1); - static const glm::vec4 currentLeafMissionColor = missionProgressColor; - static const glm::vec4 nonCurrentMissionColor(0.3, 0.3, 0.3, 1); + static const glm::vec4 nextMissionColor(0.7, 0.3, 0.3, 1); + //static const glm::vec4 missionProgressColor(0.4, 1.0, 1.0, 1); + static const glm::vec4 currentMissionColor(0.0, 0.5, 0.5, 1); + static const glm::vec4 missionProgressColor = currentMissionColor;// (0.4, 1.0, 1.0, 1); + static const glm::vec4 currentLeafMissionColor = missionProgressColor; + static const glm::vec4 nonCurrentMissionColor(0.3, 0.3, 0.3, 1); - // Add spacing - RenderFontCr(*_fontInfo, penPosition, nonCurrentMissionColor, " "); + // Add spacing + RenderFontCr(*_fontInfo, penPosition, nonCurrentMissionColor, " "); - std::list phaseTrace = mission.phaseTrace(currentTime); + std::list phaseTrace = mission.phaseTrace(currentTime); - if (phaseTrace.size()) { - std::string title = "Current Mission Phase: " + phaseTrace.back()->name(); - RenderFontCr(*_fontInfo, penPosition, missionProgressColor, title.c_str()); - double remaining = phaseTrace.back()->timeRange().end - currentTime; - float t = static_cast(1.0 - remaining / phaseTrace.back()->timeRange().duration()); - std::string progress = progressToStr(25, t); - //RenderFontCr(*_fontInfo, penPosition, missionProgressColor, - // "%.0f s %s %.1f %%", remaining, progress.c_str(), t * 100); - } - else { - RenderFontCr(*_fontInfo, penPosition, nextMissionColor, "Next Mission:"); - double remaining = mission.timeRange().start - currentTime; - RenderFontCr(*_fontInfo, penPosition, nextMissionColor, - "%.0f s", remaining); - } - - bool showAllPhases = false; - - typedef std::pair PhaseWithDepth; - std::stack S; - int pixelIndentation = 20; - S.push({ &mission, 0 }); - while (!S.empty()) { - const MissionPhase* phase = S.top().first; - int depth = S.top().second; - S.pop(); - - bool isCurrentPhase = phase->timeRange().includes(currentTime); - - penPosition.x += depth * pixelIndentation; - if (isCurrentPhase) { - double remaining = phase->timeRange().end - currentTime; - float t = static_cast(1.0 - remaining / phase->timeRange().duration()); + if (phaseTrace.size()) { + std::string title = "Current Mission Phase: " + phaseTrace.back()->name(); + RenderFontCr(*_fontInfo, penPosition, missionProgressColor, title.c_str()); + double remaining = phaseTrace.back()->timeRange().end - currentTime; + float t = static_cast(1.0 - remaining / phaseTrace.back()->timeRange().duration()); std::string progress = progressToStr(25, t); - RenderFontCr(*_fontInfo, penPosition, currentMissionColor, - "%s %s %.1f %%", - phase->name().c_str(), - progress.c_str(), - t * 100 - ); + //RenderFontCr(*_fontInfo, penPosition, missionProgressColor, + // "%.0f s %s %.1f %%", remaining, progress.c_str(), t * 100); } else { - RenderFontCr(*_fontInfo, penPosition, nonCurrentMissionColor, phase->name().c_str()); + RenderFontCr(*_fontInfo, penPosition, nextMissionColor, "Next Mission:"); + double remaining = mission.timeRange().start - currentTime; + RenderFontCr(*_fontInfo, penPosition, nextMissionColor, + "%.0f s", remaining); } - penPosition.x -= depth * pixelIndentation; - if (isCurrentPhase || showAllPhases) { - // phases are sorted increasingly by start time, and will be popped - // last-in-first-out from the stack, so add them in reversed order. - int indexLastPhase = phase->phases().size() - 1; - for (int i = indexLastPhase; 0 <= i; --i) { - S.push({ &phase->phase(i), depth + 1 }); - } - } - } - } - } + bool showAllPhases = false; + typedef std::pair PhaseWithDepth; + std::stack S; + int pixelIndentation = 20; + S.push({ &mission, 0 }); + while (!S.empty()) { + const MissionPhase* phase = S.top().first; + int depth = S.top().second; + S.pop(); + bool isCurrentPhase = phase->timeRange().includes(currentTime); - if (openspace::ImageSequencer::ref().isReady()) { - penPosition.y -= 25.f; - - glm::vec4 targetColor(0.00, 0.75, 1.00, 1); - - if (hasNewHorizons) { - try { - double lt; - glm::dvec3 p = - SpiceManager::ref().targetPosition("PLUTO", "NEW HORIZONS", "GALACTIC", {}, currentTime, lt); - psc nhPos = PowerScaledCoordinate::CreatePowerScaledCoordinate(p.x, p.y, p.z); - float a, b, c; - glm::dvec3 radii; - SpiceManager::ref().getValue("PLUTO", "RADII", radii); - a = radii.x; - b = radii.y; - float radius = (a + b) / 2.f; - float distToSurf = glm::length(nhPos.vec3()) - radius; - - RenderFont(*_fontInfo, - penPosition, - "Distance to Pluto: % .1f (KM)", - distToSurf - ); - penPosition.y -= _fontInfo->height(); - } - catch (...) { - } - } - - double remaining = openspace::ImageSequencer::ref().getNextCaptureTime() - currentTime; - float t = static_cast(1.0 - remaining / openspace::ImageSequencer::ref().getIntervalLength()); - - std::string str = SpiceManager::ref().dateFromEphemerisTime( - ImageSequencer::ref().getNextCaptureTime(), - "YYYY MON DD HR:MN:SC" - ); - - glm::vec4 active(0.6, 1, 0.00, 1); - glm::vec4 brigther_active(0.9, 1, 0.75, 1); - - if (remaining > 0) { - - std::string progress = progressToStr(25, t); - brigther_active *= (1 - t); - - RenderFontCr(*_fontInfo, - penPosition, - active * t + brigther_active, - "Next instrument activity:" - ); - - RenderFontCr(*_fontInfo, - penPosition, - active * t + brigther_active, - "%.0f s %s %.1f %%", - remaining, progress.c_str(), t * 100 - ); - - RenderFontCr(*_fontInfo, - penPosition, - active, - "Data acquisition time: %s", - str.c_str() - ); - } - std::pair nextTarget = ImageSequencer::ref().getNextTarget(); - std::pair currentTarget = ImageSequencer::ref().getCurrentTarget(); - - if (currentTarget.first > 0.0) { - int timeleft = static_cast(nextTarget.first - currentTime); - - int hour = timeleft / 3600; - int second = timeleft % 3600; - int minute = second / 60; - second = second % 60; - - std::string hh, mm, ss; - - if (hour < 10) - hh.append("0"); - if (minute < 10) - mm.append("0"); - if (second < 10) - ss.append("0"); - - hh.append(std::to_string(hour)); - mm.append(std::to_string(minute)); - ss.append(std::to_string(second)); - - RenderFontCr(*_fontInfo, - penPosition, - targetColor, - "Data acquisition adjacency: [%s:%s:%s]", - hh.c_str(), mm.c_str(), ss.c_str() - ); - -#if 0 -// Why is it (2) in the original? ---abock - //std::pair> incidentTargets = ImageSequencer::ref().getIncidentTargetList(0); - //std::pair> incidentTargets = ImageSequencer::ref().getIncidentTargetList(2); - std::string space; - glm::vec4 color; - size_t isize = incidentTargets.second.size(); - for (size_t p = 0; p < isize; p++) { - double t = static_cast(p + 1) / static_cast(isize + 1); - t = (p > isize / 2) ? 1 - t : t; - t += 0.3; - color = (p == isize / 2) ? targetColor : glm::vec4(t, t, t, 1); - - RenderFont(*_fontInfo, - penPosition, - color, - "%s%s", - space.c_str(), incidentTargets.second[p].c_str() - ); - - - for (int k = 0; k < incidentTargets.second[p].size() + 2; k++) - space += " "; - } -#endif - penPosition.y -= _fontInfo->height(); - - std::map activeMap = ImageSequencer::ref().getActiveInstruments(); - glm::vec4 firing(0.58 - t, 1 - t, 1 - t, 1); - glm::vec4 notFiring(0.5, 0.5, 0.5, 1); - - RenderFontCr(*_fontInfo, - penPosition, - active, - "Active Instruments:" - ); - - for (auto t : activeMap) { - if (t.second == false) { - RenderFont(*_fontInfo, - penPosition, - glm::vec4(0.3, 0.3, 0.3, 1), - "| |" - ); - RenderFontCr(*_fontInfo, - penPosition, - glm::vec4(0.3, 0.3, 0.3, 1), - " %5s", - t.first.c_str() - ); - - } - else { - RenderFont(*_fontInfo, - penPosition, - glm::vec4(0.3, 0.3, 0.3, 1), - "|" - ); - if (t.first == "NH_LORRI") { - RenderFont(*_fontInfo, - penPosition, - firing, - " + " + penPosition.x += depth * pixelIndentation; + if (isCurrentPhase) { + double remaining = phase->timeRange().end - currentTime; + float t = static_cast(1.0 - remaining / phase->timeRange().duration()); + std::string progress = progressToStr(25, t); + RenderFontCr(*_fontInfo, penPosition, currentMissionColor, + "%s %s %.1f %%", + phase->name().c_str(), + progress.c_str(), + t * 100 ); } + else { + RenderFontCr(*_fontInfo, penPosition, nonCurrentMissionColor, phase->name().c_str()); + } + penPosition.x -= depth * pixelIndentation; + + if (isCurrentPhase || showAllPhases) { + // phases are sorted increasingly by start time, and will be popped + // last-in-first-out from the stack, so add them in reversed order. + int indexLastPhase = phase->phases().size() - 1; + for (int i = indexLastPhase; 0 <= i; --i) { + S.push({ &phase->phase(i), depth + 1 }); + } + } + } + } + } + + + + if (openspace::ImageSequencer::ref().isReady()) { + penPosition.y -= 25.f; + + glm::vec4 targetColor(0.00, 0.75, 1.00, 1); + + if (hasNewHorizons) { + try { + double lt; + glm::dvec3 p = + SpiceManager::ref().targetPosition("PLUTO", "NEW HORIZONS", "GALACTIC", {}, currentTime, lt); + psc nhPos = PowerScaledCoordinate::CreatePowerScaledCoordinate(p.x, p.y, p.z); + float a, b, c; + glm::dvec3 radii; + SpiceManager::ref().getValue("PLUTO", "RADII", radii); + a = radii.x; + b = radii.y; + float radius = (a + b) / 2.f; + float distToSurf = glm::length(nhPos.vec3()) - radius; + + RenderFont(*_fontInfo, + penPosition, + "Distance to Pluto: % .1f (KM)", + distToSurf + ); + penPosition.y -= _fontInfo->height(); + } + catch (...) { + } + } + + double remaining = openspace::ImageSequencer::ref().getNextCaptureTime() - currentTime; + float t = static_cast(1.0 - remaining / openspace::ImageSequencer::ref().getIntervalLength()); + + std::string str = SpiceManager::ref().dateFromEphemerisTime( + ImageSequencer::ref().getNextCaptureTime(), + "YYYY MON DD HR:MN:SC" + ); + + glm::vec4 active(0.6, 1, 0.00, 1); + glm::vec4 brigther_active(0.9, 1, 0.75, 1); + + if (remaining > 0) { + + std::string progress = progressToStr(25, t); + brigther_active *= (1 - t); + + RenderFontCr(*_fontInfo, + penPosition, + active * t + brigther_active, + "Next instrument activity:" + ); + + RenderFontCr(*_fontInfo, + penPosition, + active * t + brigther_active, + "%.0f s %s %.1f %%", + remaining, progress.c_str(), t * 100 + ); + + RenderFontCr(*_fontInfo, + penPosition, + active, + "Data acquisition time: %s", + str.c_str() + ); + } + std::pair nextTarget = ImageSequencer::ref().getNextTarget(); + std::pair currentTarget = ImageSequencer::ref().getCurrentTarget(); + + if (currentTarget.first > 0.0) { + int timeleft = static_cast(nextTarget.first - currentTime); + + int hour = timeleft / 3600; + int second = timeleft % 3600; + int minute = second / 60; + second = second % 60; + + std::string hh, mm, ss; + + if (hour < 10) + hh.append("0"); + if (minute < 10) + mm.append("0"); + if (second < 10) + ss.append("0"); + + hh.append(std::to_string(hour)); + mm.append(std::to_string(minute)); + ss.append(std::to_string(second)); + + RenderFontCr(*_fontInfo, + penPosition, + targetColor, + "Data acquisition adjacency: [%s:%s:%s]", + hh.c_str(), mm.c_str(), ss.c_str() + ); + + #if 0 + // Why is it (2) in the original? ---abock + //std::pair> incidentTargets = ImageSequencer::ref().getIncidentTargetList(0); + //std::pair> incidentTargets = ImageSequencer::ref().getIncidentTargetList(2); + std::string space; + glm::vec4 color; + size_t isize = incidentTargets.second.size(); + for (size_t p = 0; p < isize; p++) { + double t = static_cast(p + 1) / static_cast(isize + 1); + t = (p > isize / 2) ? 1 - t : t; + t += 0.3; + color = (p == isize / 2) ? targetColor : glm::vec4(t, t, t, 1); + RenderFont(*_fontInfo, penPosition, - glm::vec4(0.3, 0.3, 0.3, 1), - " |" - ); - RenderFontCr(*_fontInfo, - penPosition, - active, - " %5s", - t.first.c_str() + color, + "%s%s", + space.c_str(), incidentTargets.second[p].c_str() ); + + + for (int k = 0; k < incidentTargets.second[p].size() + 2; k++) + space += " "; + } + #endif + penPosition.y -= _fontInfo->height(); + + std::map activeMap = ImageSequencer::ref().getActiveInstruments(); + glm::vec4 firing(0.58 - t, 1 - t, 1 - t, 1); + glm::vec4 notFiring(0.5, 0.5, 0.5, 1); + + RenderFontCr(*_fontInfo, + penPosition, + active, + "Active Instruments:" + ); + + for (auto t : activeMap) { + if (t.second == false) { + RenderFont(*_fontInfo, + penPosition, + glm::vec4(0.3, 0.3, 0.3, 1), + "| |" + ); + RenderFontCr(*_fontInfo, + penPosition, + glm::vec4(0.3, 0.3, 0.3, 1), + " %5s", + t.first.c_str() + ); + + } + else { + RenderFont(*_fontInfo, + penPosition, + glm::vec4(0.3, 0.3, 0.3, 1), + "|" + ); + if (t.first == "NH_LORRI") { + RenderFont(*_fontInfo, + penPosition, + firing, + " + " + ); + } + RenderFont(*_fontInfo, + penPosition, + glm::vec4(0.3, 0.3, 0.3, 1), + " |" + ); + RenderFontCr(*_fontInfo, + penPosition, + active, + " %5s", + t.first.c_str() + ); + } } } } From b5c99604cded40507eda245ee3907b3c92a3ea86 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Tue, 30 Aug 2016 10:56:41 +0200 Subject: [PATCH 13/92] Render Philae separately from Rosetta --- data/scene/rosetta/rosetta/rosetta.mod | 30 +++++++++++++++++--------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/data/scene/rosetta/rosetta/rosetta.mod b/data/scene/rosetta/rosetta/rosetta.mod index fd489a5f23..70572026ac 100644 --- a/data/scene/rosetta/rosetta/rosetta.mod +++ b/data/scene/rosetta/rosetta/rosetta.mod @@ -269,18 +269,28 @@ return { }, { Name = "Philae", - Parent = "RosettaModel", + Parent = "67PBarycenter", -- This should need a transform, but currently the model is intrinsically -- translated - -- Transform = { - -- Translation = { - -- Type = "SpiceEphemeris", - -- Body = "PHILAE", - -- Reference = "GALACTIC", - -- Observer = "ROSETTA", - -- Kernels = RosettaKernels - -- } - -- } + Transform = { + Translation = { + Type = "SpiceEphemeris", + Body = "PHILAE", + Reference = "GALACTIC", + Observer = "CHURYUMOV-GERASIMENKO", + Kernels = RosettaKernels + }, + Rotation = { + Type = "SpiceRotation", + SourceFrame = "ROS_SPACECRAFT", + DestinationFrame = "GALACTIC", + }, + Scale = { + Type = "StaticScale", + -- The scale of the model is in cm; OpenSpace is in m + Scale = 0.01 + } + } }, { Name = "Philae_foil", From abb40e24b677f091741a05a3c283c1f99c74b01b Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Tue, 30 Aug 2016 11:06:58 +0200 Subject: [PATCH 14/92] Space cleanup --- config/sgct/VRArenaSimCenter.xml | 158 +++++++++++++++--------------- config/sgct/single.xml | 32 +++--- config/sgct/single_fisheye.xml | 68 ++++++------- config/sgct/single_gui.xml | 48 ++++----- config/sgct/single_sbs_stereo.xml | 28 +++--- config/sgct/single_stereo.xml | 44 ++++----- config/sgct/single_two_win.xml | 74 +++++++------- config/sgct/two_nodes.xml | 82 ++++++++-------- 8 files changed, 267 insertions(+), 267 deletions(-) diff --git a/config/sgct/VRArenaSimCenter.xml b/config/sgct/VRArenaSimCenter.xml index 3ce0236e5f..f57ec51789 100644 --- a/config/sgct/VRArenaSimCenter.xml +++ b/config/sgct/VRArenaSimCenter.xml @@ -1,82 +1,82 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/config/sgct/single.xml b/config/sgct/single.xml index 62aea727b1..7b20bcb10c 100644 --- a/config/sgct/single.xml +++ b/config/sgct/single.xml @@ -1,24 +1,24 @@ - - - - - - - + + + + + + + - - - + + + - - - - - - + + + + + + diff --git a/config/sgct/single_fisheye.xml b/config/sgct/single_fisheye.xml index b72758eb6c..b9bc7415dd 100644 --- a/config/sgct/single_fisheye.xml +++ b/config/sgct/single_fisheye.xml @@ -1,37 +1,37 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/config/sgct/single_gui.xml b/config/sgct/single_gui.xml index e0d1b6bfa8..a3956e40f6 100644 --- a/config/sgct/single_gui.xml +++ b/config/sgct/single_gui.xml @@ -1,37 +1,37 @@ - - - - - - - + + + + + + + - - - + + + - - - - - + + + + + - - - + + + - - - - - - + + + + + + diff --git a/config/sgct/single_sbs_stereo.xml b/config/sgct/single_sbs_stereo.xml index ab3d4826fb..d92f95ed66 100644 --- a/config/sgct/single_sbs_stereo.xml +++ b/config/sgct/single_sbs_stereo.xml @@ -1,21 +1,21 @@ - - - - - - - - + + + + + + + + - - - - - - + + + + + + \ No newline at end of file diff --git a/config/sgct/single_stereo.xml b/config/sgct/single_stereo.xml index 71f83845c3..8497af6188 100644 --- a/config/sgct/single_stereo.xml +++ b/config/sgct/single_stereo.xml @@ -1,25 +1,25 @@ - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/config/sgct/single_two_win.xml b/config/sgct/single_two_win.xml index 7286afb127..4cd802423a 100644 --- a/config/sgct/single_two_win.xml +++ b/config/sgct/single_two_win.xml @@ -1,40 +1,40 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/config/sgct/two_nodes.xml b/config/sgct/two_nodes.xml index 456976ebe5..9ec00bf7bc 100644 --- a/config/sgct/two_nodes.xml +++ b/config/sgct/two_nodes.xml @@ -1,44 +1,44 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 29d50e85fe2001d7fceee2358c56599f0d98bd0c Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Tue, 30 Aug 2016 11:07:13 +0200 Subject: [PATCH 15/92] Bind keys to disable outer planets orbits --- scripts/bind_keys_rosetta.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/bind_keys_rosetta.lua b/scripts/bind_keys_rosetta.lua index 47bb50541c..6c1ec594a3 100644 --- a/scripts/bind_keys_rosetta.lua +++ b/scripts/bind_keys_rosetta.lua @@ -21,6 +21,6 @@ openspace.bindKey("F8", "openspace.setPropertyValue('67P.renderable.ProjectionCo openspace.bindKey("i", helper.renderable.toggle('ImagePlaneRosetta')) openspace.bindKey("q", helper.renderable.toggle('SunMarker')) -openspace.bindKey("e", helper.renderable.toggle('EarthMarker')) +openspace.bindKey("e", helper.renderable.toggle('JupiterTrail') .. helper.renderable.toggle('SaturnTrail') .. helper.renderable.toggle('UranusTrail') .. helper.renderable.toggle('NeptuneTrail')) openspace.bindKey("c", "openspace.parallel.setAddress('130.236.142.51');openspace.parallel.setPassword('newhorizons-20150714');openspace.parallel.connect();") From 86a0661aefa7bb5d57e853ad5c021894d6126941 Mon Sep 17 00:00:00 2001 From: Emil Axelsson Date: Tue, 30 Aug 2016 13:36:57 +0200 Subject: [PATCH 16/92] perform bias matrix operation in shader instead of on cpu, for renderableplanetprojection --- modules/newhorizons/shaders/renderablePlanetProjection_fs.glsl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/newhorizons/shaders/renderablePlanetProjection_fs.glsl b/modules/newhorizons/shaders/renderablePlanetProjection_fs.glsl index 3f6e2be3ba..d95b7a66b9 100644 --- a/modules/newhorizons/shaders/renderablePlanetProjection_fs.glsl +++ b/modules/newhorizons/shaders/renderablePlanetProjection_fs.glsl @@ -71,6 +71,8 @@ void main() { projected.x /= projected.w; projected.y /= projected.w; + projected = projected * 0.5 + vec4(0.5); + vec3 normal = normalize((ModelTransform*vec4(vertex.xyz,0)).xyz); vec3 v_b = normalize(boresight); From 34b1401d99360b22f8d01026c757c7c26beca5f8 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 1 Sep 2016 09:34:08 +0200 Subject: [PATCH 17/92] Some configuration update to 67P and key bindings --- data/scene/rosetta.scene | 13 ++++++++++--- data/scene/rosetta/67P/67P.mod | 1 + scripts/bind_keys_rosetta.lua | 1 + 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/data/scene/rosetta.scene b/data/scene/rosetta.scene index 0aa3c75884..befa637e83 100644 --- a/data/scene/rosetta.scene +++ b/data/scene/rosetta.scene @@ -9,9 +9,16 @@ function preInitialization() openspace.spice.loadKernel("${SPICE}/naif0011.tls") openspace.spice.loadKernel("${SPICE}/pck00010.tpc") - -- openspace.time.setTime("2014-08-15T03:05:18.101") - -- openspace.time.setTime("2016-08-20T03:05:18.101") - openspace.time.setTime("2014-11-12T09:00:18.101") + -- Usual start + openspace.time.setTime("2014-08-01T03:05:18.101") + + -- Philae release + -- openspace.time.setTime("2014-11-12T08:00:00.000") + + -- Shadow flyby + -- openspace.time.setTime("2015-02-14T12:00:00.000") + + -- openspace.time.setTime("2015-07-29T06:02:10.000") -- openspace.time.setTime("2014 AUG 21 18:00:00") -- openspace.time.setTime("2015 SEP 10 19:39:00") diff --git a/data/scene/rosetta/67P/67P.mod b/data/scene/rosetta/67P/67P.mod index 9c14de2e59..68f80487fb 100644 --- a/data/scene/rosetta/67P/67P.mod +++ b/data/scene/rosetta/67P/67P.mod @@ -28,6 +28,7 @@ return { Textures = { Type = "simple", Color = "textures/gray.jpg", + -- Color = "textures/may9_map.jpg", Project = "textures/defaultProj.png", Default = "textures/defaultProj.png" }, diff --git a/scripts/bind_keys_rosetta.lua b/scripts/bind_keys_rosetta.lua index 6c1ec594a3..0837db0c7c 100644 --- a/scripts/bind_keys_rosetta.lua +++ b/scripts/bind_keys_rosetta.lua @@ -22,5 +22,6 @@ openspace.bindKey("F8", "openspace.setPropertyValue('67P.renderable.ProjectionCo openspace.bindKey("i", helper.renderable.toggle('ImagePlaneRosetta')) openspace.bindKey("q", helper.renderable.toggle('SunMarker')) openspace.bindKey("e", helper.renderable.toggle('JupiterTrail') .. helper.renderable.toggle('SaturnTrail') .. helper.renderable.toggle('UranusTrail') .. helper.renderable.toggle('NeptuneTrail')) +openspace.bindKey("f", helper.renderable.toggle('PhilaeTrail')) openspace.bindKey("c", "openspace.parallel.setAddress('130.236.142.51');openspace.parallel.setPassword('newhorizons-20150714');openspace.parallel.connect();") From 0060e4782a5910cd5dc733ada479a75101e042e4 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 1 Sep 2016 09:53:56 +0200 Subject: [PATCH 18/92] Adding a configuration value to ProjectionComponent that determines the aspect ratio of the projection texture (default = 1.0) --- .../newhorizons/jupiter/callisto/callisto.mod | 1 + .../newhorizons/jupiter/europa/europa.mod | 1 + .../newhorizons/jupiter/ganymede/ganymede.mod | 1 + data/scene/newhorizons/jupiter/io/io.mod | 1 + .../newhorizons/jupiter/jupiter/jupiter.mod | 1 + .../scene/newhorizons/pluto/charon/charon.mod | 1 + data/scene/newhorizons/pluto/pluto/pluto.mod | 1 + data/scene/osirisrex/bennu/bennu.mod | 1 + .../newhorizons/util/projectioncomponent.cpp | 41 ++++++++++++++++--- .../newhorizons/util/projectioncomponent.h | 2 + 10 files changed, 45 insertions(+), 6 deletions(-) diff --git a/data/scene/newhorizons/jupiter/callisto/callisto.mod b/data/scene/newhorizons/jupiter/callisto/callisto.mod index 6eccc2d280..44bae2484b 100644 --- a/data/scene/newhorizons/jupiter/callisto/callisto.mod +++ b/data/scene/newhorizons/jupiter/callisto/callisto.mod @@ -22,6 +22,7 @@ return { Observer = "NEW HORIZONS", Target = "CALLISTO", Aberration = "NONE", + AspectRatio = 2 }, Instrument = { Name = "NH_LORRI", diff --git a/data/scene/newhorizons/jupiter/europa/europa.mod b/data/scene/newhorizons/jupiter/europa/europa.mod index c3b7e2951b..a3e9b4a882 100644 --- a/data/scene/newhorizons/jupiter/europa/europa.mod +++ b/data/scene/newhorizons/jupiter/europa/europa.mod @@ -22,6 +22,7 @@ return { Observer = "NEW HORIZONS", Target = "EUROPA", Aberration = "NONE", + AspectRatio = 2 }, Instrument = { Name = "NH_LORRI", diff --git a/data/scene/newhorizons/jupiter/ganymede/ganymede.mod b/data/scene/newhorizons/jupiter/ganymede/ganymede.mod index 37fb4d5252..11fcfe432b 100644 --- a/data/scene/newhorizons/jupiter/ganymede/ganymede.mod +++ b/data/scene/newhorizons/jupiter/ganymede/ganymede.mod @@ -22,6 +22,7 @@ return { Observer = "NEW HORIZONS", Target = "GANYMEDE", Aberration = "NONE", + AspectRatio = 2 }, Instrument = { Name = "NH_LORRI", diff --git a/data/scene/newhorizons/jupiter/io/io.mod b/data/scene/newhorizons/jupiter/io/io.mod index f98deb8d8a..76615815b8 100644 --- a/data/scene/newhorizons/jupiter/io/io.mod +++ b/data/scene/newhorizons/jupiter/io/io.mod @@ -22,6 +22,7 @@ return { Observer = "NEW HORIZONS", Target = "IO", Aberration = "NONE", + AspectRatio = 2 }, Instrument = { Name = "NH_LORRI", diff --git a/data/scene/newhorizons/jupiter/jupiter/jupiter.mod b/data/scene/newhorizons/jupiter/jupiter/jupiter.mod index 8b6af8e568..fd8222df3b 100644 --- a/data/scene/newhorizons/jupiter/jupiter/jupiter.mod +++ b/data/scene/newhorizons/jupiter/jupiter/jupiter.mod @@ -41,6 +41,7 @@ return { Observer = "NEW HORIZONS", Target = "JUPITER", Aberration = "NONE", + AspectRatio = 2 }, DataInputTranslation = { Instrument = { diff --git a/data/scene/newhorizons/pluto/charon/charon.mod b/data/scene/newhorizons/pluto/charon/charon.mod index 5f63bc524d..8fbe1de3e5 100644 --- a/data/scene/newhorizons/pluto/charon/charon.mod +++ b/data/scene/newhorizons/pluto/charon/charon.mod @@ -40,6 +40,7 @@ return { Observer = "NEW HORIZONS", Target = "CHARON", Aberration = "NONE", + AspectRatio = 2 }, Instrument = { Name = "NH_LORRI", diff --git a/data/scene/newhorizons/pluto/pluto/pluto.mod b/data/scene/newhorizons/pluto/pluto/pluto.mod index a34e52aa7b..59fe90b53b 100644 --- a/data/scene/newhorizons/pluto/pluto/pluto.mod +++ b/data/scene/newhorizons/pluto/pluto/pluto.mod @@ -67,6 +67,7 @@ return { Observer = "NEW HORIZONS", Target = "PLUTO", Aberration = "NONE", + AspectRatio = 2 }, DataInputTranslation = { Instrument = { diff --git a/data/scene/osirisrex/bennu/bennu.mod b/data/scene/osirisrex/bennu/bennu.mod index 7c558e16f8..414778e72d 100644 --- a/data/scene/osirisrex/bennu/bennu.mod +++ b/data/scene/osirisrex/bennu/bennu.mod @@ -51,6 +51,7 @@ return { Observer = "SUN", Target = BENNU_BODY, Aberration = "NONE", + AspectRatio = 2 }, DataInputTranslation = { Instruments = { diff --git a/modules/newhorizons/util/projectioncomponent.cpp b/modules/newhorizons/util/projectioncomponent.cpp index 313fcc17a7..f2e9fd7fc6 100644 --- a/modules/newhorizons/util/projectioncomponent.cpp +++ b/modules/newhorizons/util/projectioncomponent.cpp @@ -52,6 +52,7 @@ namespace { const std::string keyTranslation = "DataInputTranslation"; const std::string keyNeedsTextureMapDilation = "Projection.TextureMap"; + const std::string keyTextureMapAspectRatio = "Projection.AspectRatio"; const std::string sequenceTypeImage = "image-sequence"; const std::string sequenceTypePlaybook = "playbook"; @@ -196,6 +197,12 @@ bool ProjectionComponent::initializeProjectionSettings(const Dictionary& diction _needsTextureMapDilation = dictionary.value(keyNeedsTextureMapDilation); } + _projectionTextureAspectRatio = 1.f; + if (dictionary.hasKeyAndValue(keyTextureMapAspectRatio)) { + _projectionTextureAspectRatio = + static_cast(dictionary.value(keyTextureMapAspectRatio)); + } + return completeSuccess; } @@ -579,11 +586,22 @@ std::shared_ptr ProjectionComponent::loadProjectionTextu bool ProjectionComponent::generateProjectionLayerTexture() { int maxSize = OpenGLCap.max2DTextureSize() / 2; + glm::ivec2 size; + if (_projectionTextureAspectRatio > 1.f) { + size.x = maxSize; + size.y = static_cast(maxSize / _projectionTextureAspectRatio); + } + else { + size.x = static_cast(maxSize * _projectionTextureAspectRatio); + size.y = maxSize; + } + + LINFO( - "Creating projection texture of size '" << maxSize << ", " << maxSize / 2 << "'" + "Creating projection texture of size '" << size.x << ", " << size.y << "'" ); _projectionTexture = std::make_unique ( - glm::uvec3(maxSize, maxSize / 2, 1), + glm::uvec3(size, 1), ghoul::opengl::Texture::Format::RGBA ); if (_projectionTexture) { @@ -593,7 +611,7 @@ bool ProjectionComponent::generateProjectionLayerTexture() { if (_needsTextureMapDilation) { _dilation.texture = std::make_unique( - glm::uvec3(maxSize, maxSize / 2, 1), + glm::uvec3(size, 1), ghoul::opengl::Texture::Format::RGBA ); @@ -603,7 +621,7 @@ bool ProjectionComponent::generateProjectionLayerTexture() { } _dilation.stencilTexture = std::make_unique( - glm::uvec3(maxSize, maxSize / 2, 1), + glm::uvec3(size, 1), ghoul::opengl::Texture::Format::Red, ghoul::opengl::Texture::Format::Red ); @@ -622,12 +640,23 @@ bool ProjectionComponent::generateProjectionLayerTexture() { bool ProjectionComponent::generateDepthTexture() { int maxSize = OpenGLCap.max2DTextureSize() / 2; + glm::ivec2 size; + + if (_projectionTextureAspectRatio > 1.f) { + size.x = maxSize; + size.y = static_cast(maxSize / _projectionTextureAspectRatio); + } + else { + size.x = static_cast(maxSize * _projectionTextureAspectRatio); + size.y = maxSize; + } + LINFO( - "Creating depth texture of size '" << maxSize / 2 << ", " << maxSize / 2 << "'" + "Creating depth texture of size '" << size.x << ", " << size.y << "'" ); _depthTexture = std::make_unique( - glm::uvec3(maxSize / 2, maxSize / 2, 1), + glm::uvec3(size, 1), ghoul::opengl::Texture::Format::DepthComponent, GL_DEPTH_COMPONENT32F ); diff --git a/modules/newhorizons/util/projectioncomponent.h b/modules/newhorizons/util/projectioncomponent.h index cf061f85e1..a2f680b142 100644 --- a/modules/newhorizons/util/projectioncomponent.h +++ b/modules/newhorizons/util/projectioncomponent.h @@ -108,6 +108,8 @@ protected: std::unique_ptr _depthTexture; std::shared_ptr _placeholderTexture; + float _projectionTextureAspectRatio; + std::string _instrumentID; std::string _projectorID; std::string _projecteeID; From 33bea46d5c8803a29088884440e9da0a856050ae Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 1 Sep 2016 10:41:18 +0200 Subject: [PATCH 19/92] Remove old rosetta kernels from 67P --- data/scene/rosetta/67P/67P.data | 1 - data/scene/rosetta/67P/RosettaKernels.torrent | Bin 23149 -> 0 bytes 2 files changed, 1 deletion(-) delete mode 100644 data/scene/rosetta/67P/RosettaKernels.torrent diff --git a/data/scene/rosetta/67P/67P.data b/data/scene/rosetta/67P/67P.data index 3c899a9480..57f10bc7d3 100644 --- a/data/scene/rosetta/67P/67P.data +++ b/data/scene/rosetta/67P/67P.data @@ -5,6 +5,5 @@ return { }, TorrentFiles = { { File = "67P_rotated_5_130.obj.torrent", Destination = "obj" }, - { File = "RosettaKernels.torrent", Destination = "${SPICE}" } } } \ No newline at end of file diff --git a/data/scene/rosetta/67P/RosettaKernels.torrent b/data/scene/rosetta/67P/RosettaKernels.torrent deleted file mode 100644 index be150ad7294b78b48978915eb78a0034f15c40c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23149 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 From d9016f9a98d0de99f58de7ade2893499a550180e Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 1 Sep 2016 10:42:19 +0200 Subject: [PATCH 20/92] Fix projection fading in renderable model --- modules/newhorizons/shaders/renderableModel_fs.glsl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/newhorizons/shaders/renderableModel_fs.glsl b/modules/newhorizons/shaders/renderableModel_fs.glsl index 240aba6ea4..5fb2f6942c 100644 --- a/modules/newhorizons/shaders/renderableModel_fs.glsl +++ b/modules/newhorizons/shaders/renderableModel_fs.glsl @@ -84,12 +84,12 @@ Fragment getFragment() { color = diffuseAlbedo; } - float transparency = 1.0; - float alpha = _projectionFading * transparency; + // float transparency = 1.0; + // float alpha = _projectionFading * transparency; Fragment frag; - frag.color = vec4(color, alpha); + frag.color = vec4(color, 1.0); frag.depth = vs_positionScreenSpace.w; return frag; } From 574e6db29de520ae1a24833a92a59993e976f92e Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 1 Sep 2016 11:07:18 +0200 Subject: [PATCH 21/92] Remove the false image flipping in the renderableplanetprojection shader --- modules/newhorizons/shaders/renderablePlanetProjection_fs.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/newhorizons/shaders/renderablePlanetProjection_fs.glsl b/modules/newhorizons/shaders/renderablePlanetProjection_fs.glsl index 126d199e02..ff8698c866 100644 --- a/modules/newhorizons/shaders/renderablePlanetProjection_fs.glsl +++ b/modules/newhorizons/shaders/renderablePlanetProjection_fs.glsl @@ -85,7 +85,7 @@ void main() { { // The 1-x is in this texture call because of flipped textures // to be fixed soon ---abock - color = texture(projectionTexture, vec2(projected.x, 1-projected.y)); + color = texture(projectionTexture, vec2(projected.x, projected.y)); stencil = vec4(1.0); } else { From e3d5a9ca38aea2928fe51ecbbf3c9e3809c74eb1 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Mon, 5 Sep 2016 17:01:32 +0200 Subject: [PATCH 22/92] Cleaned up Doxygen Removed Doxygen warnings Documented Property specializations (closing #10) --- Doxyfile | 386 +----------------- ext/ghoul | 2 +- ext/sgct | 2 +- .../openspace/interaction/interactionmode.h | 4 +- include/openspace/properties/optionproperty.h | 9 +- include/openspace/properties/scalarproperty.h | 71 ++++ .../openspace/properties/templateproperty.inl | 2 +- include/openspace/rendering/abufferrenderer.h | 2 +- 8 files changed, 104 insertions(+), 374 deletions(-) diff --git a/Doxyfile b/Doxyfile index f2d2cc9a81..5217764619 100644 --- a/Doxyfile +++ b/Doxyfile @@ -1,45 +1,19 @@ -# Doxyfile 1.7.6.1 +# Doxyfile 1.8.8 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- - + DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = OpenSpace PROJECT_NUMBER = PROJECT_LOGO = OUTPUT_DIRECTORY = doc/ -CREATE_SUBDIRS = NO -OUTPUT_LANGUAGE = English -BRIEF_MEMBER_DESC = YES -REPEAT_BRIEF = YES ALWAYS_DETAILED_SEC = YES -INLINE_INHERITED_MEMB = NO -FULL_PATH_NAMES = YES JAVADOC_AUTOBRIEF = YES QT_AUTOBRIEF = YES - -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. - -ALIASES = -BUILTIN_STL_SUPPORT = NO - -SUBGROUPING = YES - -# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and -# unions are shown inside the group in which they are included (e.g. using -# @ingroup) instead of on a separate page (for HTML and Man pages) or -# section (for LaTeX and RTF). - -INLINE_GROUPED_CLASSES = NO INLINE_SIMPLE_STRUCTS = YES -TYPEDEF_HIDES_STRUCT = NO -LOOKUP_CACHE_SIZE = 1 +LOOKUP_CACHE_SIZE = 9 #--------------------------------------------------------------------------- # Build related configuration options @@ -48,405 +22,83 @@ LOOKUP_CACHE_SIZE = 1 EXTRACT_ALL = YES EXTRACT_PRIVATE = YES EXTRACT_STATIC = YES -EXTRACT_LOCAL_CLASSES = YES -EXTRACT_LOCAL_METHODS = NO -EXTRACT_ANON_NSPACES = NO -HIDE_IN_BODY_DOCS = NO -INTERNAL_DOCS = NO CASE_SENSE_NAMES = NO HIDE_SCOPE_NAMES = YES SHOW_INCLUDE_FILES = YES -FORCE_LOCAL_INCLUDES = NO INLINE_INFO = NO -SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = YES SORT_MEMBERS_CTORS_1ST = YES -SORT_GROUP_NAMES = NO -SORT_BY_SCOPE_NAME = NO -STRICT_PROTO_MATCHING = NO -GENERATE_TODOLIST = YES +GENERATE_TODOLIST = NO GENERATE_TESTLIST = NO -GENERATE_BUGLIST = YES +GENERATE_BUGLIST = NO GENERATE_DEPRECATEDLIST= YES MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = NO -SHOW_FILES = NO -SHOW_NAMESPACES = YES +SHOW_FILES = YES LAYOUT_FILE = +EXTENSION_MAPPING = inl=C++ +BUILTIN_STL_SUPPORT = YES #--------------------------------------------------------------------------- -# configuration options related to warning and progress messages +# Configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = YES -WARNINGS = YES -WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = YES WARN_FORMAT = "$file:$line: $text" #--------------------------------------------------------------------------- -# configuration options related to the input files +# Configuration options related to the input files #--------------------------------------------------------------------------- INPUT = src \ include INPUT_ENCODING = UTF-8 -FILE_PATTERNS = *.c \ - *.cpp \ +FILE_PATTERNS = *.cpp \ *.h \ *.inl RECURSIVE = YES -EXCLUDE = -EXCLUDE_SYMLINKS = NO -EXCLUDE_PATTERNS = /ext/* bin/* build/* config/* gui/* kernels/* openspace-data/* scripts/* shaders/* -EXCLUDE_SYMBOLS = +EXCLUDE_PATTERNS = ext/* bin/* build/* config/* gui/* kernels/* data/* scripts/* shaders/* +USE_MDFILE_AS_MAINPAGE = README.md #--------------------------------------------------------------------------- -# configuration options related to source browsing +# Configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = YES -INLINE_SOURCES = NO -STRIP_CODE_COMMENTS = YES -REFERENCED_BY_RELATION = NO -REFERENCES_RELATION = NO -REFERENCES_LINK_SOURCE = YES VERBATIM_HEADERS = NO #--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index +# Configuration options related to the HTML output #--------------------------------------------------------------------------- -ALPHABETICAL_INDEX = YES -COLS_IN_ALPHA_INDEX = 4 -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- - -GENERATE_HTML = YES -HTML_OUTPUT = html -HTML_FILE_EXTENSION = .html HTML_HEADER = support/doxygen/header.html HTML_FOOTER = support/doxygen/footer.html HTML_STYLESHEET = support/doxygen/stylesheet.css -#HTML_EXTRA_FILES = -HTML_COLORSTYLE_HUE = 200 -HTML_COLORSTYLE_SAT = 100 -HTML_COLORSTYLE_GAMMA = 80 -HTML_TIMESTAMP = NO -HTML_DYNAMIC_SECTIONS = NO -# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html -# for more information. -GENERATE_DOCSET = NO -DOCSET_FEEDNAME = -DOCSET_BUNDLE_ID = -DOCSET_PUBLISHER_ID = -DOCSET_PUBLISHER_NAME = -GENERATE_HTMLHELP = NO -CHM_FILE = -HHC_LOCATION = -GENERATE_CHI = NO -CHM_INDEX_ENCODING = -BINARY_TOC = NO -TOC_EXPAND = NO -DISABLE_INDEX = YES +HTML_COLORSTYLE_HUE = 225 +HTML_COLORSTYLE_SAT = 18 +HTML_COLORSTYLE_GAMMA = 100 GENERATE_TREEVIEW = YES ENUM_VALUES_PER_LINE = 6 TREEVIEW_WIDTH = 300 -EXT_LINKS_IN_WINDOW = NO -FORMULA_FONTSIZE = 10 -FORMULA_TRANSPARENT = YES -USE_MATHJAX = NO -MATHJAX_RELPATH = http://www.mathjax.org/mathjax -MATHJAX_EXTENSIONS = -SEARCHENGINE = YES -SERVER_BASED_SEARCH = NO #--------------------------------------------------------------------------- -# configuration options related to the LaTeX output +# Other output configuration options #--------------------------------------------------------------------------- - GENERATE_LATEX = NO -LATEX_OUTPUT = latex -LATEX_CMD_NAME = latex -MAKEINDEX_CMD_NAME = makeindex -COMPACT_LATEX = NO -PAPER_TYPE = a4wide -EXTRA_PACKAGES = -LATEX_HEADER = -LATEX_FOOTER = -PDF_HYPERLINKS = YES -USE_PDFLATEX = YES -LATEX_BATCHMODE = NO -LATEX_HIDE_INDICES = NO -LATEX_SOURCE_CODE = NO -LATEX_BIB_STYLE = plain - -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- - GENERATE_RTF = NO -RTF_OUTPUT = rtf -COMPACT_RTF = NO -RTF_HYPERLINKS = NO -RTF_STYLESHEET_FILE = -RTF_EXTENSIONS_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- - GENERATE_MAN = NO -MAN_OUTPUT = man -MAN_EXTENSION = .3 -MAN_LINKS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- - GENERATE_XML = NO -XML_OUTPUT = xml -XML_SCHEMA = -XML_DTD = -XML_PROGRAMLISTING = YES - -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- - GENERATE_AUTOGEN_DEF = NO - -#--------------------------------------------------------------------------- -# configuration options related to the Perl module output -#--------------------------------------------------------------------------- - GENERATE_PERLMOD = NO -PERLMOD_LATEX = NO -PERLMOD_PRETTY = YES -PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- -ENABLE_PREPROCESSING = YES MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = YES -SEARCH_INCLUDES = YES -INCLUDE_PATH = -INCLUDE_FILE_PATTERNS = -PREDEFINED = EXPAND_AS_DEFINED = YES SKIP_FUNCTION_MACROS = NO - -#--------------------------------------------------------------------------- -# Configuration::additions related to external references -#--------------------------------------------------------------------------- - -TAGFILES = -GENERATE_TAGFILE = -ALLEXTERNALS = NO -EXTERNAL_GROUPS = YES -PERL_PATH = /usr/bin/perl - -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- - -CLASS_DIAGRAMS = YES -MSCGEN_PATH = -HIDE_UNDOC_RELATIONS = YES - -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section -# have no effect if this option is set to NO (the default) - -HAVE_DOT = NO - -# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is -# allowed to run in parallel. When set to 0 (the default) doxygen will -# base this on the number of processors available in the system. You can set it -# explicitly to a value larger than 0 to get control over the balance -# between CPU load and processing speed. - -DOT_NUM_THREADS = 0 - -# By default doxygen will use the Helvetica font for all dot files that -# doxygen generates. When you want a differently looking font you can specify -# the font name using DOT_FONTNAME. You need to make sure dot is able to find -# the font, which can be done by putting it in a standard location or by setting -# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the -# directory containing the font. - -DOT_FONTNAME = Helvetica - -# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. -# The default size is 10pt. - -DOT_FONTSIZE = 10 - -# By default doxygen will tell dot to use the Helvetica font. -# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to -# set the path where dot can find it. - -DOT_FONTPATH = - -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# CLASS_DIAGRAMS tag to NO. - -CLASS_GRAPH = YES - -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and -# class references variables) of the class with other documented classes. - -COLLABORATION_GRAPH = YES - -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for groups, showing the direct groups dependencies - -GROUP_GRAPHS = YES - -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling -# Language. - -UML_LOOK = NO - -# If set to YES, the inheritance and collaboration graphs will show the -# relations between templates and their instances. - -TEMPLATE_RELATIONS = NO - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with -# other documented files. - -INCLUDE_GRAPH = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or -# indirectly include this file. - -INCLUDED_BY_GRAPH = YES - -# If the CALL_GRAPH and HAVE_DOT options are set to YES then -# doxygen will generate a call dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable call graphs -# for selected functions only using the \callgraph command. - -CALL_GRAPH = NO - -# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then -# doxygen will generate a caller dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable caller -# graphs for selected functions only using the \callergraph command. - -CALLER_GRAPH = NO - -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will generate a graphical hierarchy of all classes instead of a textual one. - -GRAPHICAL_HIERARCHY = YES - -# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories -# in a graphical way. The dependency relations are determined by the #include -# relations between the files in the directories. - -DIRECTORY_GRAPH = YES - -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are svg, png, jpg, or gif. -# If left blank png will be used. If you choose svg you need to set -# HTML_FILE_EXTENSION to xhtml in order to make the SVG files -# visible in IE 9+ (other browsers do not have this requirement). - -DOT_IMAGE_FORMAT = png - -# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to -# enable generation of interactive SVG images that allow zooming and panning. -# Note that this requires a modern browser other than Internet Explorer. -# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you -# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files -# visible. Older versions of IE do not have SVG support. - -INTERACTIVE_SVG = NO - -# The tag DOT_PATH can be used to specify the path where the dot tool can be -# found. If left blank, it is assumed the dot tool can be found in the path. - -DOT_PATH = - -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the -# \dotfile command). - -DOTFILE_DIRS = - -# The MSCFILE_DIRS tag can be used to specify one or more directories that -# contain msc files that are included in the documentation (see the -# \mscfile command). - -MSCFILE_DIRS = - -# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of -# nodes that will be shown in the graph. If the number of nodes in a graph -# becomes larger than this value, doxygen will truncate the graph, which is -# visualized by representing a node as a red box. Note that doxygen if the -# number of direct children of the root node in a graph is already larger than -# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note -# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. - -DOT_GRAPH_MAX_NODES = 50 - -# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -# graphs generated by dot. A depth value of 3 means that only nodes reachable -# from the root by following a path via at most 3 edges will be shown. Nodes -# that lay further from the root node will be omitted. Note that setting this -# option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that the size of a graph can be further restricted by -# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. - -MAX_DOT_GRAPH_DEPTH = 0 - -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not -# seem to support this out of the box. Warning: Depending on the platform used, -# enabling this option may lead to badly anti-aliased labels on the edges of -# a graph (i.e. they become hard to read). - -DOT_TRANSPARENT = NO - -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) -# support this, this feature is disabled by default. - -DOT_MULTI_TARGETS = NO - -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and -# arrows in the dot generated graphs. - -GENERATE_LEGEND = YES - -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate -# the various graphs. - -DOT_CLEANUP = YES diff --git a/ext/ghoul b/ext/ghoul index b08559d8b2..2da421b44c 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit b08559d8b2d4804348bcfb815bfbd620906e3039 +Subproject commit 2da421b44c6ab2b62a2b7c7d5ec81a4be6238c7b diff --git a/ext/sgct b/ext/sgct index 70cde82e33..8a1d737a80 160000 --- a/ext/sgct +++ b/ext/sgct @@ -1 +1 @@ -Subproject commit 70cde82e331406d8bfe406d0e606fefa89d873c7 +Subproject commit 8a1d737a8070a7c40c91d7bf24afa62feb73c8ea diff --git a/include/openspace/interaction/interactionmode.h b/include/openspace/interaction/interactionmode.h index a67938a93c..fe63e2c38b 100644 --- a/include/openspace/interaction/interactionmode.h +++ b/include/openspace/interaction/interactionmode.h @@ -186,9 +186,9 @@ public: class MouseStates { public: - /*! + /** \param sensitivity - \param velocityScalefactor can be set to 60 to remove the inertia of the + \param velocityScaleFactor can be set to 60 to remove the inertia of the interaction. Lower value will make it harder to move the camera. */ MouseStates(double sensitivity, double velocityScaleFactor); diff --git a/include/openspace/properties/optionproperty.h b/include/openspace/properties/optionproperty.h index 42bca29af6..39466779cf 100644 --- a/include/openspace/properties/optionproperty.h +++ b/include/openspace/properties/optionproperty.h @@ -60,9 +60,16 @@ public: * to its super class. * \param identifier A unique identifier for this property * \param guiName The GUI name that should be used to represent this property - * \param displayType Optional DisplayType for GUI (default RADIO) */ OptionProperty(std::string identifier, std::string guiName); + + /** + * The constructor delegating the identifier and the guiName + * to its super class. + * \param identifier A unique identifier for this property + * \param guiName The GUI name that should be used to represent this property + * \param displayType Optional DisplayType for GUI (default RADIO) + */ OptionProperty(std::string identifier, std::string guiName, DisplayType displayType); /** diff --git a/include/openspace/properties/scalarproperty.h b/include/openspace/properties/scalarproperty.h index 29cdb9100c..7576edd37d 100644 --- a/include/openspace/properties/scalarproperty.h +++ b/include/openspace/properties/scalarproperty.h @@ -25,6 +25,77 @@ #ifndef __SCALARPROPERTY_H__ #define __SCALARPROPERTY_H__ + /** + * \file scalarproperty.h + * + * \addtogroup openspace + * @{ + * \addtogroup properties + * @{ + + * \class BoolProperty + * This class is a concrete implementation of openspace::properties::TemplateProperty with + * the type bool. + + * \class CharProperty + * This class is a concrete implementation of openspace::properties::TemplateProperty with + * the type char. + + * \class SignedCharProperty + * This class is a concrete implementation of openspace::properties::TemplateProperty with + * the type signed char. + + * \class UCharProperty + * This class is a concrete implementation of openspace::properties::TemplateProperty with + * the type unsigned char. + + * \class ShortProperty + * This class is a concrete implementation of openspace::properties::TemplateProperty with + * the type short. + + * \class UShortProperty + * This class is a concrete implementation of openspace::properties::TemplateProperty with + * the type unsigned short. + + * \class IntProperty + * This class is a concrete implementation of openspace::properties::TemplateProperty with + * the type int. + + * \class UIntProperty + * This class is a concrete implementation of openspace::properties::TemplateProperty with + * the type unsigned int. + + * \class LongProperty + * This class is a concrete implementation of openspace::properties::TemplateProperty with + * the type long. + + * \class ULongProperty + * This class is a concrete implementation of openspace::properties::TemplateProperty with + * the type unsigned long. + + * \class LongLongProperty + * This class is a concrete implementation of openspace::properties::TemplateProperty with + * the type long long. + + * \class ULongLongProperty + * This class is a concrete implementation of openspace::properties::TemplateProperty with + * the type unsigned long long. + + * \class FloatProperty + * This class is a concrete implementation of openspace::properties::TemplateProperty with + * the type float. + + * \class DoubleProperty + * This class is a concrete implementation of openspace::properties::TemplateProperty with + * the type double. + + * \class LongDoubleProperty + * This class is a concrete implementation of openspace::properties::TemplateProperty with + * the type long double. + + * @} @} + */ + #include "openspace/properties/numericalproperty.h" namespace openspace { diff --git a/include/openspace/properties/templateproperty.inl b/include/openspace/properties/templateproperty.inl index 3567784124..ec8f8509a6 100644 --- a/include/openspace/properties/templateproperty.inl +++ b/include/openspace/properties/templateproperty.inl @@ -38,7 +38,7 @@ namespace properties { // C++ class name for which a typedef will be created // TYPE = The template parameter T for which the TemplateProperty is specialized #define REGISTER_TEMPLATEPROPERTY_HEADER(CLASS_NAME, TYPE) \ - typedef TemplateProperty CLASS_NAME; \ + using CLASS_NAME = TemplateProperty; \ \ template <> \ std::string PropertyDelegate>::className(); \ diff --git a/include/openspace/rendering/abufferrenderer.h b/include/openspace/rendering/abufferrenderer.h index 4a9689fa9f..8a8dd5dba6 100644 --- a/include/openspace/rendering/abufferrenderer.h +++ b/include/openspace/rendering/abufferrenderer.h @@ -105,7 +105,7 @@ private: /** * When a volume is attached or detached from the scene graph, * the resolve program needs to be recompiled. - * The #_volumes map keeps track of which volumes that can + * The _volumes map keeps track of which volumes that can * be rendered using the current resolve program, along with their raycast data * (id, namespace, etc) */ From 3785d30ff63d5520c88190e92b6c29469da8744b Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Wed, 7 Sep 2016 10:35:05 +0200 Subject: [PATCH 23/92] Ability to enable and disable the ShadowMapping --- data/scene/rosetta/67P/67P.mod | 3 +- .../rendering/renderablemodelprojection.cpp | 22 ++++---- .../newhorizons/util/projectioncomponent.cpp | 56 +++++++++++-------- .../newhorizons/util/projectioncomponent.h | 10 +++- 4 files changed, 54 insertions(+), 37 deletions(-) diff --git a/data/scene/rosetta/67P/67P.mod b/data/scene/rosetta/67P/67P.mod index 68f80487fb..d28d3874ff 100644 --- a/data/scene/rosetta/67P/67P.mod +++ b/data/scene/rosetta/67P/67P.mod @@ -42,7 +42,8 @@ return { Observer = "ROSETTA", Target = "CHURYUMOV-GERASIMENKO", Aberration = "NONE", - TextureMap = true + TextureMap = true, + ShadowMap = true }, DataInputTranslation = { Instrument = { diff --git a/modules/newhorizons/rendering/renderablemodelprojection.cpp b/modules/newhorizons/rendering/renderablemodelprojection.cpp index 5ae90d7779..17bf0da335 100644 --- a/modules/newhorizons/rendering/renderablemodelprojection.cpp +++ b/modules/newhorizons/rendering/renderablemodelprojection.cpp @@ -264,16 +264,18 @@ void RenderableModelProjection::update(const UpdateData& data) { void RenderableModelProjection::imageProjectGPU( std::shared_ptr projectionTexture) { - _projectionComponent.depthMapRenderBegin(); - _depthFboProgramObject->activate(); - _depthFboProgramObject->setUniform("ProjectorMatrix", _projectorMatrix); - _depthFboProgramObject->setUniform("ModelTransform", _transform); - _geometry->setUniforms(*_fboProgramObject); + if (_projectionComponent.needsShadowMap()) { + _projectionComponent.depthMapRenderBegin(); + _depthFboProgramObject->activate(); + _depthFboProgramObject->setUniform("ProjectorMatrix", _projectorMatrix); + _depthFboProgramObject->setUniform("ModelTransform", _transform); + _geometry->setUniforms(*_fboProgramObject); - _geometry->render(); + _geometry->render(); - _depthFboProgramObject->deactivate(); - _projectionComponent.depthMapRenderEnd(); + _depthFboProgramObject->deactivate(); + _projectionComponent.depthMapRenderEnd(); + } _projectionComponent.imageProjectBegin(); _fboProgramObject->activate(); @@ -288,10 +290,6 @@ void RenderableModelProjection::imageProjectGPU( _projectionComponent.depthTexture().bind(); _fboProgramObject->setUniform("depthTexture", unitDepthFbo); - glm::vec4 debugVector(0.0, 0.0, 0.0, 1.0); - glm::vec4 debugTransformed = _projectorMatrix * _transform * debugVector; - debugTransformed /= debugTransformed.w; - _fboProgramObject->setUniform("ProjectorMatrix", _projectorMatrix); _fboProgramObject->setUniform("ModelTransform", _transform); _fboProgramObject->setUniform("boresight", _boresight); diff --git a/modules/newhorizons/util/projectioncomponent.cpp b/modules/newhorizons/util/projectioncomponent.cpp index f2e9fd7fc6..2021e14aa9 100644 --- a/modules/newhorizons/util/projectioncomponent.cpp +++ b/modules/newhorizons/util/projectioncomponent.cpp @@ -52,6 +52,7 @@ namespace { const std::string keyTranslation = "DataInputTranslation"; const std::string keyNeedsTextureMapDilation = "Projection.TextureMap"; + const std::string keyNeedsShadowing = "Projection.ShadowMap"; const std::string keyTextureMapAspectRatio = "Projection.AspectRatio"; const std::string sequenceTypeImage = "image-sequence"; @@ -75,10 +76,12 @@ ProjectionComponent::ProjectionComponent() , _clearAllProjections("clearAllProjections", "Clear Projections", false) , _projectionFading("projectionFading", "Projection Fading", 1.f, 0.f, 1.f) , _projectionTexture(nullptr) - , _needsTextureMapDilation(false) { setName("ProjectionComponent"); + _shadowing.isEnabled = false; + _dilation.isEnabled = false; + addProperty(_performProjection); addProperty(_clearAllProjections); addProperty(_projectionFading); @@ -104,7 +107,7 @@ bool ProjectionComponent::initialize() { } _placeholderTexture = std::move(texture); - if (_needsTextureMapDilation) { + if (_dilation.isEnabled) { _dilation.program = ghoul::opengl::ProgramObject::Build( "Dilation", "${MODULE_NEWHORIZONS}/shaders/dilation_vs.glsl", @@ -147,7 +150,7 @@ bool ProjectionComponent::deinitialize() { glDeleteFramebuffers(1, &_fboID); - if (_needsTextureMapDilation) { + if (_dilation.isEnabled) { glDeleteFramebuffers(1, &_dilation.fbo); glDeleteVertexArrays(1, &_dilation.vao); glDeleteBuffers(1, &_dilation.vbo); @@ -194,7 +197,11 @@ bool ProjectionComponent::initializeProjectionSettings(const Dictionary& diction } if (dictionary.hasKeyAndValue(keyNeedsTextureMapDilation)) { - _needsTextureMapDilation = dictionary.value(keyNeedsTextureMapDilation); + _dilation.isEnabled = dictionary.value(keyNeedsTextureMapDilation); + } + + if (dictionary.hasKeyAndValue(keyNeedsShadowing)) { + _shadowing.isEnabled = dictionary.value(keyNeedsShadowing); } _projectionTextureAspectRatio = 1.f; @@ -297,17 +304,23 @@ void ProjectionComponent::imageProjectBegin() { static_cast(_projectionTexture->height()) ); - if (_needsTextureMapDilation) { + if (_dilation.isEnabled) { GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; glDrawBuffers(2, buffers); } } +bool ProjectionComponent::needsShadowMap() const { + return _shadowing.isEnabled; +} + ghoul::opengl::Texture& ProjectionComponent::depthTexture() { - return *_depthTexture; + return *_shadowing.texture; } void ProjectionComponent::depthMapRenderBegin() { + ghoul_assert(_shadowing.isEnabled, "Shadowing is not enabled"); + // keep handle to the current bound FBO glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_defaultFBO); glGetIntegerv(GL_VIEWPORT, _viewport); @@ -317,8 +330,8 @@ void ProjectionComponent::depthMapRenderBegin() { glViewport( 0, 0, - static_cast(_depthTexture->width()), - static_cast(_depthTexture->height()) + static_cast(_shadowing.texture->width()), + static_cast(_shadowing.texture->height()) ); glClear(GL_DEPTH_BUFFER_BIT); @@ -332,7 +345,7 @@ void ProjectionComponent::depthMapRenderEnd() { void ProjectionComponent::imageProjectEnd() { - if (_needsTextureMapDilation) { + if (_dilation.isEnabled) { glBindFramebuffer(GL_FRAMEBUFFER, _dilation.fbo); glDisable(GL_BLEND); @@ -361,10 +374,8 @@ void ProjectionComponent::imageProjectEnd() { } void ProjectionComponent::update() { - if (_needsTextureMapDilation) { - if (_dilation.program->isDirty()) { - _dilation.program->rebuildFromFile(); - } + if (_dilation.isEnabled && _dilation.program->isDirty()) { + _dilation.program->rebuildFromFile(); } } @@ -378,7 +389,7 @@ bool ProjectionComponent::depthRendertarget() { GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, - *_depthTexture, + *_shadowing.texture, 0); glDrawBuffer(GL_NONE); @@ -415,7 +426,7 @@ bool ProjectionComponent::auxiliaryRendertarget() { } - if (_needsTextureMapDilation) { + if (_dilation.isEnabled) { // We only need the stencil texture if we need to dilate glFramebufferTexture2D( GL_FRAMEBUFFER, @@ -497,7 +508,7 @@ float ProjectionComponent::projectionFading() const { } ghoul::opengl::Texture& ProjectionComponent::projectionTexture() const { - if (_needsTextureMapDilation) { + if (_dilation.isEnabled) { return *_dilation.texture; } else { @@ -544,7 +555,7 @@ void ProjectionComponent::clearAllProjections() { glClearColor(0.f, 0.f, 0.f, 0.f); glClear(GL_COLOR_BUFFER_BIT); - if (_needsTextureMapDilation) { + if (_dilation.isEnabled) { glBindFramebuffer(GL_FRAMEBUFFER, _dilation.fbo); glClear(GL_COLOR_BUFFER_BIT); } @@ -609,7 +620,7 @@ bool ProjectionComponent::generateProjectionLayerTexture() { //_projectionTexture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); } - if (_needsTextureMapDilation) { + if (_dilation.isEnabled) { _dilation.texture = std::make_unique( glm::uvec3(size, 1), ghoul::opengl::Texture::Format::RGBA @@ -655,16 +666,17 @@ bool ProjectionComponent::generateDepthTexture() { "Creating depth texture of size '" << size.x << ", " << size.y << "'" ); - _depthTexture = std::make_unique( + _shadowing.texture = std::make_unique( glm::uvec3(size, 1), ghoul::opengl::Texture::Format::DepthComponent, GL_DEPTH_COMPONENT32F ); - if (_depthTexture) - _depthTexture->uploadTexture(); + if (_shadowing.texture) { + _shadowing.texture->uploadTexture(); + } - return _depthTexture != nullptr; + return _shadowing.texture != nullptr; } diff --git a/modules/newhorizons/util/projectioncomponent.h b/modules/newhorizons/util/projectioncomponent.h index a2f680b142..c26cdbb323 100644 --- a/modules/newhorizons/util/projectioncomponent.h +++ b/modules/newhorizons/util/projectioncomponent.h @@ -87,6 +87,8 @@ public: bool needsClearProjection() const; float projectionFading() const; + bool needsShadowMap() const; + void clearAllProjections(); ghoul::opengl::Texture& projectionTexture() const; @@ -105,7 +107,6 @@ protected: properties::FloatProperty _projectionFading; std::unique_ptr _projectionTexture; - std::unique_ptr _depthTexture; std::shared_ptr _placeholderTexture; float _projectionTextureAspectRatio; @@ -124,8 +125,13 @@ protected: GLint _defaultFBO; GLint _viewport[4]; - bool _needsTextureMapDilation; struct { + bool isEnabled; + std::unique_ptr texture; + } _shadowing; + + struct { + bool isEnabled; GLuint fbo; GLuint vao; GLuint vbo; From 708644038409b584d7e5caf99ae98a9ed9c07c10 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Wed, 7 Sep 2016 11:24:04 +0200 Subject: [PATCH 24/92] Turn property identifier and guiName specification into prerequisites Allow NumericalProperty's min and max value to be changed after construction --- .../openspace/properties/numericalproperty.h | 3 +++ .../openspace/properties/numericalproperty.inl | 10 ++++++++++ include/openspace/properties/property.h | 2 ++ src/properties/property.cpp | 18 ++++++++---------- 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/include/openspace/properties/numericalproperty.h b/include/openspace/properties/numericalproperty.h index 33a179b7fd..ffa257a16c 100644 --- a/include/openspace/properties/numericalproperty.h +++ b/include/openspace/properties/numericalproperty.h @@ -48,7 +48,10 @@ public: bool setStringValue(std::string value) override; T minValue() const; + void setMinValue(T value); + T maxValue() const; + void setMaxValue(T value); virtual std::string className() const override; diff --git a/include/openspace/properties/numericalproperty.inl b/include/openspace/properties/numericalproperty.inl index 964c29190d..86f04e8f62 100644 --- a/include/openspace/properties/numericalproperty.inl +++ b/include/openspace/properties/numericalproperty.inl @@ -329,11 +329,21 @@ T NumericalProperty::minValue() const { return _minimumValue; } +template +void NumericalProperty::setMinValue(T value) { + _minimumValue = std::move(value); +} + template T NumericalProperty::maxValue() const { return _maximumValue; } +template +void NumericalProperty::setMaxValue(T value) { + _maximumValue = std::move(value); +} + template std::string NumericalProperty::generateAdditionalDescription() const { std::string result; diff --git a/include/openspace/properties/property.h b/include/openspace/properties/property.h index 3ec235e341..c3cdb71572 100644 --- a/include/openspace/properties/property.h +++ b/include/openspace/properties/property.h @@ -71,6 +71,8 @@ public: * \param identifier A unique identifier for this property. It has to be unique to the * PropertyOwner and cannot contain any .s * \param guiName The human-readable GUI name for this Property + * \pre \p identifier must not be empty + * \pre \p guiName must not be empty */ Property(std::string identifier, std::string guiName); diff --git a/src/properties/property.cpp b/src/properties/property.cpp index 3f0253b136..265789fadb 100644 --- a/src/properties/property.cpp +++ b/src/properties/property.cpp @@ -55,10 +55,8 @@ Property::Property(std::string identifier, std::string guiName) : _owner(nullptr) , _identifier(std::move(identifier)) { - if (_identifier.empty()) - LWARNING("Property identifier is empty"); - if (guiName.empty()) - LWARNING("Property GUI name is empty"); + ghoul_assert(!_identifier.empty(), "Identifier must not be empty"); + ghoul_assert(!guiName.empty(), "guiName must not be empty"); setVisible(true); _metaData.setValue(MetaDataKeyGuiName, std::move(guiName)); @@ -75,8 +73,9 @@ std::string Property::fullyQualifiedIdentifier() const { PropertyOwner* currentOwner = owner(); while (currentOwner) { std::string ownerId = currentOwner->name(); - if (!ownerId.empty()) + if (!ownerId.empty()) { identifier = ownerId + "." + identifier; + } currentOwner = currentOwner->owner(); } return identifier; @@ -162,19 +161,18 @@ void Property::onChange(std::function callback) { _onChangeCallback = std::move(callback); } -PropertyOwner* Property::owner() const -{ +PropertyOwner* Property::owner() const { return _owner; } -void Property::setPropertyOwner(PropertyOwner* owner) -{ +void Property::setPropertyOwner(PropertyOwner* owner) { _owner = owner; } void Property::notifyListener() { - if (_onChangeCallback) + if (_onChangeCallback) { _onChangeCallback(); + } } std::string Property::generateBaseDescription() const { From 69f72718c02a677151675a53520cd0a687af738e Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Wed, 7 Sep 2016 14:16:16 +0200 Subject: [PATCH 25/92] Enable the change of projection texture size in ProjectionComponent (closing #105) Make the Shadowmapping in RenderableModelProjection optional by setting a value in the mod file --- ext/ghoul | 2 +- .../rendering/renderablemodelprojection.cpp | 8 +- .../newhorizons/util/projectioncomponent.cpp | 247 +++++++++++++++--- .../newhorizons/util/projectioncomponent.h | 12 +- 4 files changed, 231 insertions(+), 38 deletions(-) diff --git a/ext/ghoul b/ext/ghoul index 2da421b44c..2c2099f161 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 2da421b44c6ab2b62a2b7c7d5ec81a4be6238c7b +Subproject commit 2c2099f161df8fd33ce857660a047a89ba472d4b diff --git a/modules/newhorizons/rendering/renderablemodelprojection.cpp b/modules/newhorizons/rendering/renderablemodelprojection.cpp index 17bf0da335..c621428ae8 100644 --- a/modules/newhorizons/rendering/renderablemodelprojection.cpp +++ b/modules/newhorizons/rendering/renderablemodelprojection.cpp @@ -286,9 +286,11 @@ void RenderableModelProjection::imageProjectGPU( _fboProgramObject->setUniform("projectionTexture", unitFbo); ghoul::opengl::TextureUnit unitDepthFbo; - unitDepthFbo.activate(); - _projectionComponent.depthTexture().bind(); - _fboProgramObject->setUniform("depthTexture", unitDepthFbo); + if (_projectionComponent.needsShadowMap()) { + unitDepthFbo.activate(); + _projectionComponent.depthTexture().bind(); + _fboProgramObject->setUniform("depthTexture", unitDepthFbo); + } _fboProgramObject->setUniform("ProjectorMatrix", _projectorMatrix); _fboProgramObject->setUniform("ModelTransform", _transform); diff --git a/modules/newhorizons/util/projectioncomponent.cpp b/modules/newhorizons/util/projectioncomponent.cpp index 2021e14aa9..21a36cbd61 100644 --- a/modules/newhorizons/util/projectioncomponent.cpp +++ b/modules/newhorizons/util/projectioncomponent.cpp @@ -33,6 +33,7 @@ #include #include +#include #include #include @@ -69,12 +70,16 @@ namespace { namespace openspace { using ghoul::Dictionary; +using glm::ivec2; ProjectionComponent::ProjectionComponent() : properties::PropertyOwner() , _performProjection("performProjection", "Perform Projections", true) , _clearAllProjections("clearAllProjections", "Clear Projections", false) , _projectionFading("projectionFading", "Projection Fading", 1.f, 0.f, 1.f) + , _textureSize("textureSize", "Texture Size", ivec2(16), ivec2(16), ivec2(32768)) + , _applyTextureSize("applyTextureSize", "Apply Texture Size") + , _textureSizeDirty(false) , _projectionTexture(nullptr) { setName("ProjectionComponent"); @@ -85,11 +90,33 @@ ProjectionComponent::ProjectionComponent() addProperty(_performProjection); addProperty(_clearAllProjections); addProperty(_projectionFading); + + addProperty(_textureSize); + addProperty(_applyTextureSize); + _applyTextureSize.onChange([this]() { _textureSizeDirty = true; }); } bool ProjectionComponent::initialize() { - bool success = generateProjectionLayerTexture(); - success &= generateDepthTexture(); + int maxSize = OpenGLCap.max2DTextureSize(); + glm::ivec2 size; + + if (_projectionTextureAspectRatio > 1.f) { + size.x = maxSize; + size.y = static_cast(maxSize / _projectionTextureAspectRatio); + } + else { + size.x = static_cast(maxSize * _projectionTextureAspectRatio); + size.y = maxSize; + } + + _textureSize.setMaxValue(size); + _textureSize = size / 2; + + // We only want to use half the resolution per default: + size /= 2; + + bool success = generateProjectionLayerTexture(size); + success &= generateDepthTexture(size); success &= auxiliaryRendertarget(); success &= depthRendertarget(); @@ -295,6 +322,190 @@ void ProjectionComponent::imageProjectBegin() { // keep handle to the current bound FBO glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_defaultFBO); + if (_textureSizeDirty) { + LDEBUG("Changing texture size to " << std::to_string(_textureSize)); + + // If the texture size has changed, we have to allocate new memory and copy + // the image texture to the new target + + using ghoul::opengl::Texture; + using ghoul::opengl::FramebufferObject; + + // Make a copy of the old textures + std::unique_ptr oldProjectionTexture = std::move(_projectionTexture); + std::unique_ptr oldDilationStencil = std::move(_dilation.stencilTexture); + std::unique_ptr oldDilationTexture = std::move(_dilation.texture); + std::unique_ptr oldDepthTexture = std::move(_shadowing.texture); + + // Generate the new textures + generateProjectionLayerTexture(_textureSize); + + if (_shadowing.isEnabled) { + generateDepthTexture(_textureSize); + } + + auto copyFramebuffers = [](Texture* src, Texture* dst, const std::string& msg) { + glFramebufferTexture( + GL_READ_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + *src, + 0 + ); + + GLenum status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER); + if (!FramebufferObject::errorChecking(status).empty()) { + LERROR( + "Read Buffer (" << msg << "): " << + FramebufferObject::errorChecking(status) + ); + } + + glFramebufferTexture( + GL_DRAW_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + *dst, + 0 + ); + + status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); + if (!FramebufferObject::errorChecking(status).empty()) { + LERROR( + "Draw Buffer (" << msg << "): " << + FramebufferObject::errorChecking(status) + ); + } + + glBlitFramebuffer( + 0, 0, + src->dimensions().x, src->dimensions().y, + 0, 0, + dst->dimensions().x, dst->dimensions().y, + GL_COLOR_BUFFER_BIT, + GL_LINEAR + ); + }; + + auto copyDepthBuffer = [](Texture* src, Texture* dst, const std::string& msg) { + glFramebufferTexture( + GL_READ_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + *src, + 0 + ); + + GLenum status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER); + if (!FramebufferObject::errorChecking(status).empty()) { + LERROR( + "Read Buffer (" << msg << "): " << + FramebufferObject::errorChecking(status) + ); + } + + glFramebufferTexture( + GL_DRAW_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + *dst, + 0 + ); + + status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); + if (!FramebufferObject::errorChecking(status).empty()) { + LERROR( + "Draw Buffer (" << msg << "): " << + FramebufferObject::errorChecking(status) + ); + } + + glBlitFramebuffer( + 0, 0, + src->dimensions().x, src->dimensions().y, + 0, 0, + dst->dimensions().x, dst->dimensions().y, + GL_DEPTH_BUFFER_BIT, + GL_NEAREST + ); + }; + + GLuint fbos[2]; + glGenFramebuffers(2, fbos); + glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]); + + copyFramebuffers( + oldProjectionTexture.get(), + _projectionTexture.get(), + "Projection" + ); + + if (_dilation.isEnabled) { + copyFramebuffers( + oldDilationStencil.get(), + _dilation.stencilTexture.get(), + "Dilation Stencil" + ); + + copyFramebuffers( + oldDilationTexture.get(), + _dilation.texture.get(), + "Dilation Texture" + ); + } + + if (_shadowing.isEnabled) { + copyDepthBuffer( + oldDepthTexture.get(), + _shadowing.texture.get(), + "Shadowing" + ); + } + + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glDeleteFramebuffers(2, fbos); + + glBindFramebuffer(GL_FRAMEBUFFER, _fboID); + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + *_projectionTexture, + 0 + ); + + if (_dilation.isEnabled) { + // We only need the stencil texture if we need to dilate + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT1, + GL_TEXTURE_2D, + *_dilation.stencilTexture, + 0 + ); + + glBindFramebuffer(GL_FRAMEBUFFER, _dilation.fbo); + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + *_dilation.texture, + 0 + ); + } + + if (_shadowing.isEnabled) { + glBindFramebuffer(GL_FRAMEBUFFER, _depthFboID); + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + GL_TEXTURE_2D, + *_shadowing.texture, + 0 + ); + } + + _textureSizeDirty = false; + } + glGetIntegerv(GL_VIEWPORT, _viewport); glBindFramebuffer(GL_FRAMEBUFFER, _fboID); @@ -342,8 +553,6 @@ void ProjectionComponent::depthMapRenderEnd() { glViewport(_viewport[0], _viewport[1], _viewport[2], _viewport[3]); } - - void ProjectionComponent::imageProjectEnd() { if (_dilation.isEnabled) { glBindFramebuffer(GL_FRAMEBUFFER, _dilation.fbo); @@ -594,20 +803,7 @@ std::shared_ptr ProjectionComponent::loadProjectionTextu return std::move(texture); } -bool ProjectionComponent::generateProjectionLayerTexture() { - int maxSize = OpenGLCap.max2DTextureSize() / 2; - - glm::ivec2 size; - if (_projectionTextureAspectRatio > 1.f) { - size.x = maxSize; - size.y = static_cast(maxSize / _projectionTextureAspectRatio); - } - else { - size.x = static_cast(maxSize * _projectionTextureAspectRatio); - size.y = maxSize; - } - - +bool ProjectionComponent::generateProjectionLayerTexture(const ivec2& size) { LINFO( "Creating projection texture of size '" << size.x << ", " << size.y << "'" ); @@ -648,20 +844,7 @@ bool ProjectionComponent::generateProjectionLayerTexture() { } -bool ProjectionComponent::generateDepthTexture() { - int maxSize = OpenGLCap.max2DTextureSize() / 2; - - glm::ivec2 size; - - if (_projectionTextureAspectRatio > 1.f) { - size.x = maxSize; - size.y = static_cast(maxSize / _projectionTextureAspectRatio); - } - else { - size.x = static_cast(maxSize * _projectionTextureAspectRatio); - size.y = maxSize; - } - +bool ProjectionComponent::generateDepthTexture(const ivec2& size) { LINFO( "Creating depth texture of size '" << size.x << ", " << size.y << "'" ); diff --git a/modules/newhorizons/util/projectioncomponent.h b/modules/newhorizons/util/projectioncomponent.h index c26cdbb323..9a38a233e2 100644 --- a/modules/newhorizons/util/projectioncomponent.h +++ b/modules/newhorizons/util/projectioncomponent.h @@ -27,6 +27,8 @@ #include #include +#include +#include #include #include @@ -63,8 +65,6 @@ public: void update(); - bool generateProjectionLayerTexture(); - bool generateDepthTexture(); bool auxiliaryRendertarget(); bool depthRendertarget(); @@ -101,11 +101,19 @@ public: float fieldOfViewY() const; float aspectRatio() const; +private: + bool generateProjectionLayerTexture(const glm::ivec2& size); + bool generateDepthTexture(const glm::ivec2& size); + protected: properties::BoolProperty _performProjection; properties::BoolProperty _clearAllProjections; properties::FloatProperty _projectionFading; + properties::IVec2Property _textureSize; + properties::TriggerProperty _applyTextureSize; + bool _textureSizeDirty; + std::unique_ptr _projectionTexture; std::shared_ptr _placeholderTexture; From f909c32ddec15b67ae34297ee0817200971a7707 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Wed, 7 Sep 2016 16:31:52 +0200 Subject: [PATCH 26/92] Add single_4k.xml configuration file for high resolution screenshots --- config/sgct/single_4k.xml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 config/sgct/single_4k.xml diff --git a/config/sgct/single_4k.xml b/config/sgct/single_4k.xml new file mode 100644 index 0000000000..cb4dd6339c --- /dev/null +++ b/config/sgct/single_4k.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + From 68918610584dfe1ae76953e6fd1fd4a6284cdf90 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Wed, 7 Sep 2016 16:32:19 +0200 Subject: [PATCH 27/92] Add server request script used for the DownloadManager --- support/server/request.wsgi | 53 +++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 support/server/request.wsgi diff --git a/support/server/request.wsgi b/support/server/request.wsgi new file mode 100644 index 0000000000..abefb3d51d --- /dev/null +++ b/support/server/request.wsgi @@ -0,0 +1,53 @@ +import os.path +import imp +from cgi import parse_qs, escape + +responseHeader = [('Content-Type', 'text/plain')] + +baseUrl = %REQUIRED% URL TO THE BASE DIRECTORY OF FILES +baseFile = %REQUIRED% LOCAL PATH TO THE BASE DIRECTORY OF FILES +baseRequest = %REQUIRED% LOCAL PATH TO THE DIRECTORY OF REQUESTS + +def find_file(identifier, file_version, application_version): + file = identifier + "_v" + application_version + "_v" + file_version + + if os.path.isfile(baseFile + file): + # If the direct file exists, it lists all necessary files line by line + with open(baseFile + file, "r") as f: + return True, f.read() + elif os.path.isfile(baseRequest + file + '.py'): + # If the direct file doesn't exist, we look for a python script that + # will generate the returns string dynamically + module = imp.load_source('files', baseRequest + file + '.py') + return True, module.files() + else: + # If neither exists, an unknown file was requested + return False, "Could not find identifier '" + file + "'" + +def application(environ, start_response): + parameters = parse_qs(environ.get('QUERY_STRING', '')) + + if 'identifier' in parameters: + file = escape(parameters['identifier'][0]) + else: + start_response('400 Bad Request', responseHeader) + return ['No identifier provided'] + + if 'file_version' in parameters: + file_version = escape(parameters['file_version'][0]) + else: + file_version = "1" + + if 'application_version' in parameters: + application_version = escape(parameters['application_version'][0]) + else: + application_version = "1" + + status_ok, url = find_file(file, file_version, application_version) + + if (status_ok): + start_response('200 OK', responseHeader) + else: + start_response('400 Bad Request', responseHeader) + + return [url] \ No newline at end of file From 95b1a2a1add617f4103051fc276cd2bc398c0355 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Wed, 7 Sep 2016 17:21:08 +0200 Subject: [PATCH 28/92] Make the RenderableModelProjection shader work without a depth map --- .../rendering/renderablemodelprojection.cpp | 2 + .../shaders/renderableModelProjection_fs.glsl | 49 +++++++++++++------ 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/modules/newhorizons/rendering/renderablemodelprojection.cpp b/modules/newhorizons/rendering/renderablemodelprojection.cpp index c621428ae8..3daadde566 100644 --- a/modules/newhorizons/rendering/renderablemodelprojection.cpp +++ b/modules/newhorizons/rendering/renderablemodelprojection.cpp @@ -285,6 +285,8 @@ void RenderableModelProjection::imageProjectGPU( projectionTexture->bind(); _fboProgramObject->setUniform("projectionTexture", unitFbo); + _fboProgramObject->setUniform("needShadowMap", _projectionComponent.needsShadowMap()); + ghoul::opengl::TextureUnit unitDepthFbo; if (_projectionComponent.needsShadowMap()) { unitDepthFbo.activate(); diff --git a/modules/newhorizons/shaders/renderableModelProjection_fs.glsl b/modules/newhorizons/shaders/renderableModelProjection_fs.glsl index d45177bd43..6a96de92f2 100644 --- a/modules/newhorizons/shaders/renderableModelProjection_fs.glsl +++ b/modules/newhorizons/shaders/renderableModelProjection_fs.glsl @@ -36,6 +36,8 @@ layout (location = 1) out vec4 stencil; uniform sampler2D projectionTexture; uniform sampler2D depthTexture; +uniform bool needShadowMap; + uniform mat4 ModelTransform; uniform vec3 boresight; uniform vec4 debugColor; @@ -45,21 +47,38 @@ bool inRange(float x, float a, float b) { } void main() { - vec3 n = normalize(vs_normal.xyz); - vec4 projected = vs_ndc; - vec2 uv = vec2(0.5) * projected.xy + vec2(0.5); + vec3 n = normalize(vs_normal.xyz); + vec4 projected = vs_ndc; + vec2 uv = vec2(0.5) * projected.xy + vec2(0.5); - float thisDepth = projected.z * 0.5 + 0.5; - float closestDepth = texture(depthTexture, uv).r; - float epsilon = 0.001; + if (needShadowMap) { + float thisDepth = projected.z * 0.5 + 0.5; + float closestDepth = texture(depthTexture, uv).r; + float epsilon = 0.001; - if (inRange(uv.x, 0.0, 1.0) && inRange(uv.y, 0.0, 1.0) && - dot(n, boresight) < 0 && thisDepth <= closestDepth + epsilon) { - color = texture(projectionTexture, vec2(1.0) - uv); - color.a = 1.0; - stencil = vec4(1.0); - } else { - color = vec4(vec3(0.0), 0.0); - stencil = vec4(0.0); - } + if (inRange(uv.x, 0.0, 1.0) && inRange(uv.y, 0.0, 1.0) && + dot(n, boresight) < 0 && thisDepth <= closestDepth + epsilon) + { + color = texture(projectionTexture, vec2(1.0) - uv); + color.a = 1.0; + stencil = vec4(1.0); + } + else { + color = vec4(vec3(0.0), 0.0); + stencil = vec4(0.0); + } + } + else { + if (inRange(uv.x, 0.0, 1.0) && inRange(uv.y, 0.0, 1.0) && + dot(n, boresight) < 0) + { + color = texture(projectionTexture, vec2(1.0) - uv); + color.a = 1.0; + stencil = vec4(1.0); + } + else { + color = vec4(vec3(0.0), 0.0); + stencil = vec4(0.0); + } + } } From 965f3eded0e7250208714c0fb498ef23c72b8219 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 8 Sep 2016 13:22:34 +0200 Subject: [PATCH 29/92] Clang compile fixes --- modules/base/rendering/modelgeometry.cpp | 6 +++--- modules/newhorizons/util/projectioncomponent.h | 2 +- src/interaction/interactionhandler.cpp | 4 ++-- src/scene/scenegraphnode.cpp | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/base/rendering/modelgeometry.cpp b/modules/base/rendering/modelgeometry.cpp index 507e38ce81..655c883a2e 100644 --- a/modules/base/rendering/modelgeometry.cpp +++ b/modules/base/rendering/modelgeometry.cpp @@ -125,9 +125,9 @@ bool ModelGeometry::initialize(Renderable* parent) { for (auto v: _vertices) { maximumDistanceSquared = glm::max( - glm::pow(v.location[0], 2) + - glm::pow(v.location[1], 2) + - glm::pow(v.location[2], 2), maximumDistanceSquared); + glm::pow(v.location[0], 2.f) + + glm::pow(v.location[1], 2.f) + + glm::pow(v.location[2], 2.f), maximumDistanceSquared); } _parent->setBoundingSphere(PowerScaledScalar(glm::sqrt(maximumDistanceSquared), 0.0)); diff --git a/modules/newhorizons/util/projectioncomponent.h b/modules/newhorizons/util/projectioncomponent.h index 9a38a233e2..6bae9afa6f 100644 --- a/modules/newhorizons/util/projectioncomponent.h +++ b/modules/newhorizons/util/projectioncomponent.h @@ -56,7 +56,7 @@ public: bool initializeProjectionSettings(const ghoul::Dictionary& dictionary); bool initializeParser(const ghoul::Dictionary& dictionary); - ghoul::opengl::Texture& ProjectionComponent::depthTexture(); + ghoul::opengl::Texture& depthTexture(); void imageProjectBegin(); void imageProjectEnd(); void depthMapRenderBegin(); diff --git a/src/interaction/interactionhandler.cpp b/src/interaction/interactionhandler.cpp index f1bf90b1aa..a496a6b636 100644 --- a/src/interaction/interactionhandler.cpp +++ b/src/interaction/interactionhandler.cpp @@ -1019,14 +1019,14 @@ void InteractionHandler::clearKeyframes() { } void InteractionHandler::serialize(SyncBuffer* syncBuffer) { - for each (auto var in _interactionModes) + for (auto var : _interactionModes) { var.second->serialize(syncBuffer); } } void InteractionHandler::deserialize(SyncBuffer* syncBuffer) { - for each (auto var in _interactionModes) + for (auto var : _interactionModes) { var.second->deserialize(syncBuffer); } diff --git a/src/scene/scenegraphnode.cpp b/src/scene/scenegraphnode.cpp index 370a1692be..3ac738de27 100644 --- a/src/scene/scenegraphnode.cpp +++ b/src/scene/scenegraphnode.cpp @@ -592,7 +592,7 @@ SceneGraphNode* SceneGraphNode::childNode(const std::string& name) void SceneGraphNode::updateCamera(Camera* camera) const{ - psc origin = worldPosition(); + psc origin(worldPosition()); //int i = 0; // the camera position From 037630073254b684ebcd864cd341262fa62598bc Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 8 Sep 2016 15:32:27 +0200 Subject: [PATCH 30/92] Update Ghoul Change TriangleSoup and StatsCollector to use new Boolean class --- ext/ghoul | 2 +- include/openspace/rendering/renderable.h | 4 +- modules/globebrowsing/meshes/trianglesoup.cpp | 6 +-- modules/globebrowsing/meshes/trianglesoup.h | 10 ++-- modules/globebrowsing/other/statscollector.h | 5 +- src/rendering/renderable.cpp | 49 +++++++------------ 6 files changed, 31 insertions(+), 45 deletions(-) diff --git a/ext/ghoul b/ext/ghoul index 2c2099f161..7e91a75120 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 2c2099f161df8fd33ce857660a047a89ba472d4b +Subproject commit 7e91a75120d0810a6998741573d88fe05c1c1b96 diff --git a/include/openspace/rendering/renderable.h b/include/openspace/rendering/renderable.h index 7a669cc700..7b11fc2511 100644 --- a/include/openspace/rendering/renderable.h +++ b/include/openspace/rendering/renderable.h @@ -71,8 +71,8 @@ public: virtual bool isReady() const = 0; bool isEnabled() const; - void setBoundingSphere(const PowerScaledScalar& boundingSphere); - const PowerScaledScalar& getBoundingSphere(); + void setBoundingSphere(PowerScaledScalar boundingSphere); + PowerScaledScalar getBoundingSphere(); virtual void render(const RenderData& data); virtual void render(const RenderData& data, RendererTasks& rendererTask); diff --git a/modules/globebrowsing/meshes/trianglesoup.cpp b/modules/globebrowsing/meshes/trianglesoup.cpp index adfbad88e8..2d8c1e29ad 100644 --- a/modules/globebrowsing/meshes/trianglesoup.cpp +++ b/modules/globebrowsing/meshes/trianglesoup.cpp @@ -36,9 +36,9 @@ TriangleSoup::TriangleSoup(std::vector elements, : _vaoID(0) ,_vertexBufferID(0) ,_elementBufferID(0) - ,_useVertexPositions(usePositions == Positions::Yes) - ,_useTextureCoordinates(useTextures == TextureCoordinates::Yes) - ,_useVertexNormals(useNormals == Normals::Yes) + ,_useVertexPositions(usePositions) + ,_useTextureCoordinates(useTextures) + ,_useVertexNormals(useNormals) { setElements(elements); } diff --git a/modules/globebrowsing/meshes/trianglesoup.h b/modules/globebrowsing/meshes/trianglesoup.h index d2291e8a66..1f1666a2b5 100644 --- a/modules/globebrowsing/meshes/trianglesoup.h +++ b/modules/globebrowsing/meshes/trianglesoup.h @@ -25,6 +25,7 @@ #ifndef __TRIANGLESOUP_H__ #define __TRIANGLESOUP_H__ +#include #include #include @@ -44,12 +45,11 @@ namespace openspace { // TODO : Possibly render triangle strips in this class instead of triangles since // that is faster -class TriangleSoup -{ +class TriangleSoup { public: - enum class Positions { Yes, No }; - enum class TextureCoordinates { Yes, No }; - enum class Normals { Yes, No }; + using Positions = ghoul::Boolean; + using TextureCoordinates = ghoul::Boolean; + using Normals = ghoul::Boolean; TriangleSoup( std::vector elements, // At least elements are required diff --git a/modules/globebrowsing/other/statscollector.h b/modules/globebrowsing/other/statscollector.h index e5b07d8920..3bb73728fa 100644 --- a/modules/globebrowsing/other/statscollector.h +++ b/modules/globebrowsing/other/statscollector.h @@ -24,6 +24,7 @@ #ifndef __STATS_TRACKER_H__ #define __STATS_TRACKER_H__ +#include #include #include @@ -143,13 +144,13 @@ namespace openspace { StatsCollector() = delete; - enum class Enabled { Yes, No }; + using Enabled = ghoul::Boolean; StatsCollector(const std::string& filename, int dumpEveryXRecord, Enabled enabled = Enabled::Yes, const std::string& delimiter = ",") : _filename(filename) , _dumpEveryXRecord(dumpEveryXRecord) , _recordsSinceLastDump(0) - , _enabled(enabled == Enabled::Yes) + , _enabled(enabled) , _delimiter(delimiter) , _hasWrittenHeader(false) , i(TemplatedStatsCollector(_enabled, delimiter)) diff --git a/src/rendering/renderable.cpp b/src/rendering/renderable.cpp index 9ed37b4e4b..14db2e226b 100644 --- a/src/rendering/renderable.cpp +++ b/src/rendering/renderable.cpp @@ -22,14 +22,12 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -// open space includes #include #include #include #include #include -// ghoul #include #include #include @@ -75,9 +73,7 @@ Renderable::Renderable() , _startTime("") , _endTime("") , _hasTimeInterval(false) -{ - -} +{} Renderable::Renderable(const ghoul::Dictionary& dictionary) : _enabled("enabled", "Is Enabled", true) @@ -87,52 +83,41 @@ Renderable::Renderable(const ghoul::Dictionary& dictionary) , _hasTimeInterval(false) { setName("renderable"); -#ifndef NDEBUG - std::string name; - ghoul_assert(dictionary.getValue(SceneGraphNode::KeyName, name), - "Scenegraphnode need to specify '" << SceneGraphNode::KeyName - << "' because renderables is going to use this for debugging!"); -#endif + + ghoul_assert( + dictionary.hasKeyAndValue(SceneGraphNode::KeyName), + "SceneGraphNode must specify '" << SceneGraphNode::KeyName << "'" + ); dictionary.getValue(keyStart, _startTime); dictionary.getValue(keyEnd, _endTime); - if (_startTime != "" && _endTime != "") + if (_startTime != "" && _endTime != "") { _hasTimeInterval = true; + } addProperty(_enabled); } -Renderable::~Renderable() { +Renderable::~Renderable() {} + +void Renderable::setBoundingSphere(PowerScaledScalar boundingSphere) { + boundingSphere_ = std::move(boundingSphere); } -void Renderable::setBoundingSphere(const PowerScaledScalar& boundingSphere) -{ - boundingSphere_ = boundingSphere; -} - -const PowerScaledScalar& Renderable::getBoundingSphere() -{ +PowerScaledScalar Renderable::getBoundingSphere() { return boundingSphere_; } -void Renderable::update(const UpdateData&) -{ -} +void Renderable::update(const UpdateData&) {} -void Renderable::render(const RenderData& data, RendererTasks& tasks) -{ - (void) tasks; +void Renderable::render(const RenderData& data, RendererTasks&) { render(data); } -void Renderable::render(const RenderData& data) -{ -} +void Renderable::render(const RenderData& data) {} -void Renderable::postRender(const RenderData& data) -{ -} +void Renderable::postRender(const RenderData& data) {} void Renderable::setPscUniforms( ghoul::opengl::ProgramObject& program, From 32ca42ebaa6e4e64efffdeac176063b1c1cacb2d Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Mon, 12 Sep 2016 19:50:59 +0200 Subject: [PATCH 31/92] Some work on the Decoder and ImageParser to make the ownership of data more clear --- modules/newhorizons/util/decoder.cpp | 26 +++++------- modules/newhorizons/util/decoder.h | 11 +++-- modules/newhorizons/util/hongkangparser.cpp | 6 +-- modules/newhorizons/util/hongkangparser.h | 3 +- modules/newhorizons/util/imagesequencer.cpp | 13 +++--- modules/newhorizons/util/imagesequencer.h | 2 +- .../util/instrumenttimesparser.cpp | 2 +- .../newhorizons/util/instrumenttimesparser.h | 8 +--- modules/newhorizons/util/labelparser.cpp | 40 ++++++++++--------- modules/newhorizons/util/labelparser.h | 3 +- modules/newhorizons/util/sequenceparser.cpp | 3 ++ modules/newhorizons/util/sequenceparser.h | 9 +++-- 12 files changed, 65 insertions(+), 61 deletions(-) diff --git a/modules/newhorizons/util/decoder.cpp b/modules/newhorizons/util/decoder.cpp index 865815035a..74e1c9b87a 100644 --- a/modules/newhorizons/util/decoder.cpp +++ b/modules/newhorizons/util/decoder.cpp @@ -23,8 +23,11 @@ ****************************************************************************************/ #include + #include + #include +#include namespace { const std::string _loggerCat = "Decoder"; @@ -32,29 +35,22 @@ const std::string _loggerCat = "Decoder"; namespace openspace { -Decoder* Decoder::createFromDictionary(const ghoul::Dictionary& dictionary, const std::string& type) +std::unique_ptr Decoder::createFromDictionary( + const ghoul::Dictionary& dictionary, const std::string& type) { ghoul::TemplateFactory* factory = FactoryManager::ref().factory(); Decoder* result = factory->create(type, dictionary); if (result == nullptr) { - LERROR("Failed creating Payload object of type '" << type << "'"); - return nullptr; + throw ghoul::RuntimeError( + "Failed creating payload object of type '" + type + '"', + "Decoder" + ); } - return result; + return std::unique_ptr(result); } -Decoder::Decoder() -{ -} - -Decoder::Decoder(const ghoul::Dictionary& dictionary) -{ -} - -Decoder::~Decoder() -{ -} +Decoder::~Decoder() {} } // namespace openspace \ No newline at end of file diff --git a/modules/newhorizons/util/decoder.h b/modules/newhorizons/util/decoder.h index c4e2c9eb56..700cf06452 100644 --- a/modules/newhorizons/util/decoder.h +++ b/modules/newhorizons/util/decoder.h @@ -26,20 +26,23 @@ #define __DECODER_H__ #include -#include + +#include namespace openspace { class Decoder { public: - static Decoder* createFromDictionary(const ghoul::Dictionary& dictionary, const std::string& type); + static std::unique_ptr createFromDictionary( + const ghoul::Dictionary& dictionary, const std::string& type); - Decoder(const ghoul::Dictionary& dictionary); virtual ~Decoder(); + virtual std::string getDecoderType() = 0; virtual std::vector getTranslation() = 0; + protected: - Decoder(); + Decoder() = default; }; } // namespace openspace diff --git a/modules/newhorizons/util/hongkangparser.cpp b/modules/newhorizons/util/hongkangparser.cpp index 57034403d8..bd8a20b7ac 100644 --- a/modules/newhorizons/util/hongkangparser.cpp +++ b/modules/newhorizons/util/hongkangparser.cpp @@ -75,10 +75,10 @@ HongKangParser::HongKangParser(std::string name, std::string fileName, ghoul::Dictionary decoderDictionary; translationDictionary.getValue(currentKey, decoderDictionary); - Decoder* decoder = Decoder::createFromDictionary(decoderDictionary, decoders[i]); + auto decoder = Decoder::createFromDictionary(decoderDictionary, decoders[i]); //insert decoder to map - this will be used in the parser to determine //behavioral characteristics of each instrument - _fileTranslation[keys[j]] = decoder; + _fileTranslation[keys[j]] = std::move(decoder); } } //Hong's playbook needs _only_ instrument translation though. @@ -201,7 +201,7 @@ bool HongKangParser::create() { if (it->second->getDecoderType() == "SCANNER"){ // SCANNER START scan_start = time; - InstrumentDecoder* scanner = static_cast(it->second); + InstrumentDecoder* scanner = static_cast(it->second.get()); std::string endNominal = scanner->getStopCommand(); // store current position in file diff --git a/modules/newhorizons/util/hongkangparser.h b/modules/newhorizons/util/hongkangparser.h index ef1db0023d..a1959c923e 100644 --- a/modules/newhorizons/util/hongkangparser.h +++ b/modules/newhorizons/util/hongkangparser.h @@ -46,7 +46,6 @@ public: bool create() override; void findPlaybookSpecifiedTarget(std::string line, std::string& target); - virtual std::map getTranslation(){ return _fileTranslation; }; private: double getMetFromET(double et); @@ -70,7 +69,7 @@ private: std::string _name; std::string _fileName; std::string _spacecraft; - std::map _fileTranslation; + std::map> _fileTranslation; std::vector _potentialTargets; }; diff --git a/modules/newhorizons/util/imagesequencer.cpp b/modules/newhorizons/util/imagesequencer.cpp index 1a7eec7fdf..234c29c644 100644 --- a/modules/newhorizons/util/imagesequencer.cpp +++ b/modules/newhorizons/util/imagesequencer.cpp @@ -338,7 +338,7 @@ void ImageSequencer::runSequenceParser(SequenceParser* parser){ bool parserComplete = parser->create(); if (parserComplete){ // get new data - std::map translations = parser->getTranslation(); // in1 + std::map>& translations = parser->getTranslation(); // in1 std::map imageData = parser->getSubsetMap(); // in2 std::vector> instrumentTimes = parser->getIstrumentTimes(); //in3 std::vector> targetTimes = parser->getTargetTimes(); //in4 @@ -349,11 +349,14 @@ void ImageSequencer::runSequenceParser(SequenceParser* parser){ LERROR("Missing sequence data"); return; } - + // append data - _fileTranslation.insert(translations.begin(), translations.end()); - for (auto it : imageData){ + for (auto& it : translations) { + _fileTranslation[it.first] = std::move(it.second); + } + + for (auto& it : imageData){ if (_subsetMap.find(it.first) == _subsetMap.end()) { // if key not exist yet - add sequence data for key (target) _subsetMap.insert(it); @@ -404,7 +407,7 @@ void ImageSequencer::runSequenceParser(SequenceParser* parser){ sortData(); // extract payload from _fileTranslation - for (auto t : _fileTranslation){ + for (auto& t : _fileTranslation){ if (t.second->getDecoderType() == "CAMERA" || t.second->getDecoderType() == "SCANNER"){ std::vector spiceIDs = t.second->getTranslation(); diff --git a/modules/newhorizons/util/imagesequencer.h b/modules/newhorizons/util/imagesequencer.h index 07f981cc9c..4729dab641 100644 --- a/modules/newhorizons/util/imagesequencer.h +++ b/modules/newhorizons/util/imagesequencer.h @@ -152,7 +152,7 @@ private: * \see Decoder * \see (projection mod files) */ - std::map _fileTranslation; + std::map> _fileTranslation; /* * This is the main container of image data. The key is the target name, diff --git a/modules/newhorizons/util/instrumenttimesparser.cpp b/modules/newhorizons/util/instrumenttimesparser.cpp index 2d058e2dee..0454113d33 100644 --- a/modules/newhorizons/util/instrumenttimesparser.cpp +++ b/modules/newhorizons/util/instrumenttimesparser.cpp @@ -65,7 +65,7 @@ InstrumentTimesParser::InstrumentTimesParser( for (const auto& instrumentKey : instruments.keys()) { ghoul::Dictionary instrument = instruments.value(instrumentKey); ghoul::Dictionary files = instrument.value(KeyInstrumentFiles); - _fileTranslation[instrumentKey] = Decoder::createFromDictionary(instrument, KeyInstrument); + _fileTranslation[instrumentKey] = std::move(Decoder::createFromDictionary(instrument, KeyInstrument)); for (int i = 0; i < files.size(); i++) { std::string filename = files.value(std::to_string(i + 1)); _instrumentFiles[instrumentKey].push_back(filename); diff --git a/modules/newhorizons/util/instrumenttimesparser.h b/modules/newhorizons/util/instrumenttimesparser.h index 4674cc73c3..49fc2c3a4d 100644 --- a/modules/newhorizons/util/instrumenttimesparser.h +++ b/modules/newhorizons/util/instrumenttimesparser.h @@ -45,13 +45,7 @@ public: bool create() override; - //virtual std::map getTranslation() override; - - // temporary need to figure this out - std::map getTranslation(){ return _fileTranslation; }; - private: - std::regex _pattern; std::map> _instrumentFiles; @@ -59,7 +53,7 @@ private: std::string _name; std::string _fileName; std::string _spacecraft; - std::map _fileTranslation; + std::map> _fileTranslation; std::vector _specsOfInterest; std::string _target; diff --git a/modules/newhorizons/util/labelparser.cpp b/modules/newhorizons/util/labelparser.cpp index 3ce4c5271b..abd88fa532 100644 --- a/modules/newhorizons/util/labelparser.cpp +++ b/modules/newhorizons/util/labelparser.cpp @@ -22,18 +22,22 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include -#include -#include -#include -#include +#include + #include + +#include +#include + +#include +#include +#include + #include #include #include #include -#include namespace { const std::string _loggerCat = "LabelParser"; @@ -54,24 +58,24 @@ LabelParser::LabelParser(std::string name, std::string fileName, //get the different instrument types const std::vector& decoders = translationDictionary.keys(); //for each decoder (assuming might have more if hong makes changes) - for (int i = 0; i < decoders.size(); i++){ + for (int i = 0; i < decoders.size(); ++i) { ghoul::Dictionary typeDictionary; translationDictionary.getValue(decoders[i], typeDictionary); //create dictionary containing all {playbookKeys , spice IDs} - if (decoders[i] == "Instrument"){ + if (decoders[i] == "Instrument") { //for each playbook call -> create a Decoder object - const std::vector& keys = typeDictionary.keys(); - for (int j = 0; j < keys.size(); j++){ + std::vector keys = typeDictionary.keys(); + for (int j = 0; j < keys.size(); ++j){ std::string currentKey = decoders[i] + "." + keys[j]; - ghoul::Dictionary decoderDictionary; - translationDictionary.getValue(currentKey, decoderDictionary); + ghoul::Dictionary decoderDictionary = + translationDictionary.value(currentKey); - Decoder *decoder = Decoder::createFromDictionary(decoderDictionary, decoders[i]); + auto decoder = Decoder::createFromDictionary(decoderDictionary, decoders[i]); //insert decoder to map - this will be used in the parser to determine //behavioral characteristics of each instrument - _fileTranslation[keys[j]] = decoder; + _fileTranslation[keys[j]] = std::move(decoder); } } if (decoders[i] == "Target"){ @@ -91,17 +95,17 @@ LabelParser::LabelParser(std::string name, std::string fileName, for (int j = 0; j < keys.size(); j++){ ghoul::Dictionary itemDictionary; convertDictionary.getValue(keys[j], itemDictionary); - Decoder *decoder = Decoder::createFromDictionary(itemDictionary, decoders[i]); + auto decoder = Decoder::createFromDictionary(itemDictionary, decoders[i]); //insert decoder to map - this will be used in the parser to determine //behavioral characteristics of each instrument - _fileTranslation[keys[j]] = decoder; + _fileTranslation[keys[j]] = std::move(decoder); }; } } } std::string LabelParser::decode(std::string line){ - for (auto key : _fileTranslation){ + for (auto& key : _fileTranslation){ std::size_t value = line.find(key.first); if (value != std::string::npos){ std::string toTranslate = line.substr(value); @@ -121,7 +125,7 @@ std::string LabelParser::decode(std::string line){ } std::string LabelParser::encode(std::string line) { - for (auto key : _fileTranslation) { + for (auto& key : _fileTranslation) { std::size_t value = line.find(key.first); if (value != std::string::npos) { return line.substr(value); diff --git a/modules/newhorizons/util/labelparser.h b/modules/newhorizons/util/labelparser.h index c0cf393ce6..a65eaf1543 100644 --- a/modules/newhorizons/util/labelparser.h +++ b/modules/newhorizons/util/labelparser.h @@ -43,7 +43,7 @@ public: bool create() override; // temporary need to figure this out - std::map getTranslation(){ return _fileTranslation; }; + //std::map getTranslation() { return _fileTranslation; }; private: void createImage(Image& image, @@ -64,7 +64,6 @@ private: std::string _name; std::string _fileName; std::string _spacecraft; - std::map _fileTranslation; std::vector _specsOfInterest; std::string _target; diff --git a/modules/newhorizons/util/sequenceparser.cpp b/modules/newhorizons/util/sequenceparser.cpp index 340c3bdb62..e121b5f630 100644 --- a/modules/newhorizons/util/sequenceparser.cpp +++ b/modules/newhorizons/util/sequenceparser.cpp @@ -52,6 +52,9 @@ std::vector SequenceParser::getCaptureProgression(){ return _captureProgression; }; +std::map>& SequenceParser::getTranslation() { + return _fileTranslation; +} template void writeToBuffer(std::vector& buffer, size_t& currentWriteLocation, T value) { diff --git a/modules/newhorizons/util/sequenceparser.h b/modules/newhorizons/util/sequenceparser.h index 18dd755b2c..48e4989485 100644 --- a/modules/newhorizons/util/sequenceparser.h +++ b/modules/newhorizons/util/sequenceparser.h @@ -28,14 +28,15 @@ #include #include +#include + #include +#include #include #include namespace openspace { -class Decoder; - struct Image { TimeRange timeRange; std::string path; @@ -56,7 +57,7 @@ public: virtual std::map getSubsetMap() final; virtual std::vector> getIstrumentTimes() final; virtual std::vector> getTargetTimes() final; - virtual std::map getTranslation() = 0; + std::map>& getTranslation(); virtual std::vector getCaptureProgression() final; protected: @@ -67,6 +68,8 @@ protected: std::vector> _targetTimes; std::vector _captureProgression; + std::map> _fileTranslation; + NetworkEngine::MessageIdentifier _messageIdentifier; }; From 9135f6141a5d958d06879287db3a933a769f7cd0 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Mon, 12 Sep 2016 20:38:48 +0200 Subject: [PATCH 32/92] Fix crash with parser getting being destroyed prematurely --- modules/newhorizons/util/imagesequencer.cpp | 2 +- modules/newhorizons/util/sequenceparser.cpp | 2 +- modules/newhorizons/util/sequenceparser.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/newhorizons/util/imagesequencer.cpp b/modules/newhorizons/util/imagesequencer.cpp index 234c29c644..e5e1f5233e 100644 --- a/modules/newhorizons/util/imagesequencer.cpp +++ b/modules/newhorizons/util/imagesequencer.cpp @@ -340,7 +340,7 @@ void ImageSequencer::runSequenceParser(SequenceParser* parser){ // get new data std::map>& translations = parser->getTranslation(); // in1 std::map imageData = parser->getSubsetMap(); // in2 - std::vector> instrumentTimes = parser->getIstrumentTimes(); //in3 + std::vector> instrumentTimes = parser->getInstrumentTimes(); //in3 std::vector> targetTimes = parser->getTargetTimes(); //in4 std::vector captureProgression = parser->getCaptureProgression(); //in5 diff --git a/modules/newhorizons/util/sequenceparser.cpp b/modules/newhorizons/util/sequenceparser.cpp index e121b5f630..6e36361fa6 100644 --- a/modules/newhorizons/util/sequenceparser.cpp +++ b/modules/newhorizons/util/sequenceparser.cpp @@ -42,7 +42,7 @@ namespace openspace { std::map SequenceParser::getSubsetMap(){ return _subsetMap; } -std::vector> SequenceParser::getIstrumentTimes(){ +std::vector> SequenceParser::getInstrumentTimes(){ return _instrumentTimes; } std::vector> SequenceParser::getTargetTimes(){ diff --git a/modules/newhorizons/util/sequenceparser.h b/modules/newhorizons/util/sequenceparser.h index 48e4989485..258a2b566a 100644 --- a/modules/newhorizons/util/sequenceparser.h +++ b/modules/newhorizons/util/sequenceparser.h @@ -55,7 +55,7 @@ class SequenceParser { public: virtual bool create() = 0; virtual std::map getSubsetMap() final; - virtual std::vector> getIstrumentTimes() final; + virtual std::vector> getInstrumentTimes() final; virtual std::vector> getTargetTimes() final; std::map>& getTranslation(); virtual std::vector getCaptureProgression() final; From 5192f312fb254fd65683b37c9a3f1da5ba6d6a17 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Mon, 12 Sep 2016 20:39:14 +0200 Subject: [PATCH 33/92] Enable LabelParser to load different file extensions by querying the TextureReader supported extensions (closing #89) --- modules/newhorizons/util/labelparser.cpp | 45 +++++++++++++----------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/modules/newhorizons/util/labelparser.cpp b/modules/newhorizons/util/labelparser.cpp index abd88fa532..bccdb49ff6 100644 --- a/modules/newhorizons/util/labelparser.cpp +++ b/modules/newhorizons/util/labelparser.cpp @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -236,29 +237,31 @@ bool LabelParser::create() { LINFO("Please make sure input data adheres to format https://pds.jpl.nasa.gov/documents/qs/labels.html"); } } - if (count == _specsOfInterest.size()){ - count = 0; - std::string ext = "jpg"; - path.replace(path.begin() + position, path.end(), ext); - bool fileExists = FileSys.fileExists(path); - if (!fileExists) { - ext = "JPG"; - path.replace(path.begin() + position, path.end(), ext); - fileExists = FileSys.fileExists(path); - } - if (fileExists) { - Image image; - std::vector spiceInstrument; - spiceInstrument.push_back(_instrumentID); - createImage(image, startTime, stopTime, spiceInstrument, _target, path); - - _subsetMap[image.target]._subset.push_back(image); - _subsetMap[image.target]._range.include(startTime); + if (count == _specsOfInterest.size()) { + using ghoul::io::TextureReader; + auto extensions = TextureReader::ref().supportedExtensions(); - _captureProgression.push_back(startTime); - std::stable_sort(_captureProgression.begin(), _captureProgression.end()); + count = 0; + + using namespace std::literals; + std::string p = path.substr(0, path.size() - ("lbl"s).size()); + for (const std::string& ext : extensions) { + path = p + ext; + if (FileSys.fileExists(path)) { + Image image; + std::vector spiceInstrument; + spiceInstrument.push_back(_instrumentID); + createImage(image, startTime, stopTime, spiceInstrument, _target, path); + + _subsetMap[image.target]._subset.push_back(image); + _subsetMap[image.target]._range.include(startTime); + + _captureProgression.push_back(startTime); + std::stable_sort(_captureProgression.begin(), _captureProgression.end()); + + break; + } } - } } while (!file.eof()); } From 8f4f4c101fecb05c1a114543a1d1302e1fb07db3 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Tue, 13 Sep 2016 15:29:03 +0200 Subject: [PATCH 34/92] Updated Ghoul repository --- ext/ghoul | 2 +- include/openspace/rendering/renderable.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/ext/ghoul b/ext/ghoul index 7e91a75120..5120a2d60b 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 7e91a75120d0810a6998741573d88fe05c1c1b96 +Subproject commit 5120a2d60b61303369c305e66c4fcd334c249a02 diff --git a/include/openspace/rendering/renderable.h b/include/openspace/rendering/renderable.h index 7b11fc2511..36cbf1d20b 100644 --- a/include/openspace/rendering/renderable.h +++ b/include/openspace/rendering/renderable.h @@ -1,4 +1,3 @@ - /***************************************************************************************** * * * OpenSpace * From a3dde8da4168c8ade095b2a7a4a1a22c78b79eb4 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Tue, 13 Sep 2016 15:30:11 +0200 Subject: [PATCH 35/92] First working implementation of automatic documentation generation --- include/openspace/util/documentation.h | 361 +++++++++++++++++++++++++ src/CMakeLists.txt | 1 + 2 files changed, 362 insertions(+) create mode 100644 include/openspace/util/documentation.h diff --git a/include/openspace/util/documentation.h b/include/openspace/util/documentation.h new file mode 100644 index 0000000000..5cec2aee9a --- /dev/null +++ b/include/openspace/util/documentation.h @@ -0,0 +1,361 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __DOCUMENTATION_H__ +#define __DOCUMENTATION_H__ + +#include +#include + +#include +#include +#include +#include +#include + +namespace openspace { +namespace documentation { + +struct AbstractVerifier { + using Success = bool; + using Offender = std::vector; + using TestResult = std::tuple; + + virtual TestResult operator()(const ghoul::Dictionary& dict, const std::string& key) const { + bool testSuccess = test(dict, key); + if (testSuccess) { + return { testSuccess, {} }; + } + else { + return { testSuccess, {key} }; + } + } + + virtual bool test(const ghoul::Dictionary& dict, const std::string& key) const { + return false; + }; + + virtual std::string documentation() const = 0; +}; + + +struct DocumentationEntry { + DocumentationEntry(std::string key, AbstractVerifier* t, bool optional = false, std::string doc = "") + : key(std::move(key)) + , tester(std::move(t)) + , optional(optional) + , documentation(std::move(doc)) {} + + std::string key; + std::unique_ptr tester; + bool optional; + std::string documentation; +}; + +using Documentation = std::vector; + + +std::tuple> testSpecification(const Documentation& d, const ghoul::Dictionary& dictionary) { + bool success = true; + std::vector offenders; + + for (const auto& p : d) { + AbstractVerifier& verifier = *(p.tester); + AbstractVerifier::TestResult res = verifier(dictionary, p.key); + if (!std::get<0>(res)) { + success = false; + offenders.insert( + offenders.end(), + std::get<1>(res).begin(), + std::get<1>(res).end() + ); + } + } + return { success, offenders }; +} + +std::string generateDocumentation(const Documentation& d) { + using namespace std::string_literals; + std::string result; + + for (const auto& p : d) { + result += p.key + '\n'; + result += "Optional: "s + (p.optional ? "true" : "false") + '\n'; + result += p.tester->documentation() + '\n'; + result += '\n'; + result += p.documentation + '\n'; + } + + return result; +} + +template +struct TemplateVerifier : public AbstractVerifier { + using Type = T; +}; + +struct BoolVerifier : public TemplateVerifier { + bool test(const ghoul::Dictionary& dict, const std::string& key) const override { + return dict.hasKeyAndValue(key); + } + + std::string documentation() const override { + return "Type: Boolean"; + } +}; + +struct DoubleVerifier : public TemplateVerifier { + bool test(const ghoul::Dictionary& dict, const std::string& key) const override { + return dict.hasKeyAndValue(key); + } + + std::string documentation() const override { + return "Type: Double"; + } +}; + +struct IntVerifier : public TemplateVerifier { + bool test(const ghoul::Dictionary& dict, const std::string& key) const override { + if (dict.hasKeyAndValue(key)) { + return true; + } + else { + if (dict.hasKeyAndValue(key)) { + // If we have a double value, we need to check if it is integer + double value = dict.value(key); + double intPart; + return modf(value, &intPart) == 0.0; + } + else { + // If we don't have a double value, we cannot have an int value + return false; + } + } + } + + std::string documentation() const override { + return "Type: Integer"; + } +}; + +struct StringVerifier : public TemplateVerifier { + bool test(const ghoul::Dictionary& dict, const std::string& key) const override { + return dict.hasKeyAndValue(key); + } + + std::string documentation() const override { + return "Type: String"; + } +}; + +struct TableVerifier : public TemplateVerifier { + TableVerifier(Documentation d) : doc(std::move(d)) {} + + TestResult operator()(const ghoul::Dictionary& dict, const std::string& key) const override { + if (dict.hasKeyAndValue(key)) { + ghoul::Dictionary d = dict.value(key); + AbstractVerifier::TestResult res = testSpecification(doc, d); + + for (std::string& s : std::get<1>(res)) { + s = key + "." + s; + } + + return res; + } + return{ dict.hasKeyAndValue(key), {} }; + } + + std::string documentation() const override { + return "Type: Table" + '\n' + generateDocumentation(doc); + } + + Documentation doc; +}; + +template +struct LessVerifier : public T { + LessVerifier(typename T::Type value) : value(std::move(value)) {} + + bool test(const ghoul::Dictionary& dict, const std::string& key) const override { + return T::test(dict, key) && dict.value(key) < value; + } + + std::string documentation() const override { + return T::documentation() + '\n' + "Less than: " + std::to_string(value); + } + + typename T::Type value; +}; + +template +struct LessEqualVerifier : public T { + LessEqualVerifier(typename T::Type value) : value(std::move(value)) {} + + bool test(const ghoul::Dictionary& dict, const std::string& key) const override { + return T::test(dict, key) && dict.value(key) <= value; + } + + std::string documentation() const override { + return T::documentation() + '\n' + "Less or equal to: " + std::to_string(value); + } + + typename T::Type value; +}; + +template +struct GreaterVerifier : public T { + GreaterVerifier(typename T::Type value) : value(std::move(value)) {} + + bool test(const ghoul::Dictionary& dict, const std::string& key) const override { + return T::test(dict, key) && dict.value(key) > value; + } + + std::string documentation() const override { + return T::documentation() + '\n' + "Greater than: " + std::to_string(value); + } + + typename T::Type value; +}; + +template +struct GreaterEqualVerifier : public T { + GreaterEqualVerifier(typename T::Type value) : value(std::move(value)) {} + + bool test(const ghoul::Dictionary& dict, const std::string& key) const override { + return T::test(dict, key) && dict.value(key) >= value; + } + + std::string documentation() const override { + return T::documentation() + '\n' + "Greater or equal to: " + std::to_string(value); + } + + typename T::Type value; +}; + +template +struct EqualVerifier : public T { + EqualVerifier(typename T::Type value) : value(std::move(value)) {} + + bool test(const ghoul::Dictionary& dict, const std::string& key) const override { + return T::test(dict, key) && dict.value(key) == value; + } + + std::string documentation() const override { + return T::documentation() + '\n' + "Equal to: " + std::to_string(value); + } + + typename T::Type value; +}; + +template +struct UnequalVerifier : public T { + UnequalVerifier(typename T::Type value) : value(std::move(value)) {} + + bool test(const ghoul::Dictionary& dict, const std::string& key) const override { + return T::test(dict, key) && dict.value(key) != value; + } + + std::string documentation() const override { + return T::documentation() + '\n' + "Unequal to: " + std::to_string(value); + } + + typename T::Type value; +}; + +template +struct InListVerifier : public T { + InListVerifier(std::vector values) : values(std::move(values)) {} + + bool test(const ghoul::Dictionary& dict, const std::string& key) const override { + if (T::test(dict, key)) { + typename T::Type value = dict.value(key); + + auto it = std::find(values.begin(), values.end(), value); + return it != values.end(); + } + else { + return false; + } + } + + std::string documentation() const override { + std::string result = T::documentation() + '\n' + "In list {"; + + std::stringstream s; + std::copy(values.begin(), values.end(), std::ostream_iterator(s, ",")); + + std::string joined = s.str(); + // We need to remove a trailing ',' at the end of the string + result += joined.substr(0, joined.size() - 1); + + result += "}"; + return result; + } + + std::vector values; +}; + +template +struct NotInListVerifier : public T { + NotInListVerifier(std::vector values) : values(std::move(values)) {} + + bool test(const ghoul::Dictionary& dict, const std::string& key) const override { + if (T::test(dict, key)) { + typename T::Type value = dict.value(key); + + auto it = std::find(values.begin(), values.end(), value); + return it == values.end(); + } + else { + return false; + } + } + + std::string documentation() const override { + std::string result = T::documentation() + '\n' + "Not in list {"; + + std::stringstream s; + std::copy(values.begin(), values.end(), std::ostream_iterator(s, ",")); + + std::string joined = s.str(); + // We need to remove a trailing ',' at the end of the string + result += joined.substr(0, joined.size() - 1); + + + result += "}"; + return result; + } + + std::vector values; +}; + + + + + + +} // namespace documentation +} // namespace openspace + +#endif // __DOCUMENTATION_H__ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 718429a4e2..9b0a640699 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -172,6 +172,7 @@ set(OPENSPACE_HEADER ${OPENSPACE_BASE_DIR}/include/openspace/util/blockplaneintersectiongeometry.h ${OPENSPACE_BASE_DIR}/include/openspace/util/boxgeometry.h ${OPENSPACE_BASE_DIR}/include/openspace/util/camera.h + ${OPENSPACE_BASE_DIR}/include/openspace/util/documentation.h ${OPENSPACE_BASE_DIR}/include/openspace/util/factorymanager.h ${OPENSPACE_BASE_DIR}/include/openspace/util/factorymanager.inl ${OPENSPACE_BASE_DIR}/include/openspace/util/keys.h From 9c7bd2af67b9138ae78fc34295fed1e6ce3c0367 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Tue, 13 Sep 2016 16:27:42 +0200 Subject: [PATCH 36/92] Restructuring documentation code --- include/openspace/util/documentation.h | 268 ++++++----------------- include/openspace/util/documentation.inl | 188 ++++++++++++++++ src/CMakeLists.txt | 2 + src/util/documentation.cpp | 154 +++++++++++++ 4 files changed, 408 insertions(+), 204 deletions(-) create mode 100644 include/openspace/util/documentation.inl create mode 100644 src/util/documentation.cpp diff --git a/include/openspace/util/documentation.h b/include/openspace/util/documentation.h index 5cec2aee9a..ec06629316 100644 --- a/include/openspace/util/documentation.h +++ b/include/openspace/util/documentation.h @@ -37,325 +37,185 @@ namespace openspace { namespace documentation { -struct AbstractVerifier { - using Success = bool; - using Offender = std::vector; - using TestResult = std::tuple; +struct TestResult { + bool success; + std::vector offenders; +}; - virtual TestResult operator()(const ghoul::Dictionary& dict, const std::string& key) const { - bool testSuccess = test(dict, key); - if (testSuccess) { - return { testSuccess, {} }; - } - else { - return { testSuccess, {key} }; - } - } +struct Verifier { + virtual TestResult operator()(const ghoul::Dictionary& dict, + const std::string& key) const; - virtual bool test(const ghoul::Dictionary& dict, const std::string& key) const { - return false; - }; + virtual bool test(const ghoul::Dictionary& dict, const std::string& key) const; virtual std::string documentation() const = 0; }; struct DocumentationEntry { - DocumentationEntry(std::string key, AbstractVerifier* t, bool optional = false, std::string doc = "") - : key(std::move(key)) - , tester(std::move(t)) - , optional(optional) - , documentation(std::move(doc)) {} + DocumentationEntry(std::string key, Verifier* t, bool optional = false, + std::string doc = ""); std::string key; - std::unique_ptr tester; + std::shared_ptr tester; bool optional; std::string documentation; }; using Documentation = std::vector; +TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& dictionary); -std::tuple> testSpecification(const Documentation& d, const ghoul::Dictionary& dictionary) { - bool success = true; - std::vector offenders; - - for (const auto& p : d) { - AbstractVerifier& verifier = *(p.tester); - AbstractVerifier::TestResult res = verifier(dictionary, p.key); - if (!std::get<0>(res)) { - success = false; - offenders.insert( - offenders.end(), - std::get<1>(res).begin(), - std::get<1>(res).end() - ); - } - } - return { success, offenders }; -} - -std::string generateDocumentation(const Documentation& d) { - using namespace std::string_literals; - std::string result; - - for (const auto& p : d) { - result += p.key + '\n'; - result += "Optional: "s + (p.optional ? "true" : "false") + '\n'; - result += p.tester->documentation() + '\n'; - result += '\n'; - result += p.documentation + '\n'; - } - - return result; -} +std::string generateDocumentation(const Documentation& d); +// General verifiers template -struct TemplateVerifier : public AbstractVerifier { +struct TemplateVerifier : public Verifier { using Type = T; }; struct BoolVerifier : public TemplateVerifier { - bool test(const ghoul::Dictionary& dict, const std::string& key) const override { - return dict.hasKeyAndValue(key); - } + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string documentation() const override { - return "Type: Boolean"; - } + std::string documentation() const override; }; struct DoubleVerifier : public TemplateVerifier { - bool test(const ghoul::Dictionary& dict, const std::string& key) const override { - return dict.hasKeyAndValue(key); - } + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string documentation() const override { - return "Type: Double"; - } + std::string documentation() const override; }; struct IntVerifier : public TemplateVerifier { - bool test(const ghoul::Dictionary& dict, const std::string& key) const override { - if (dict.hasKeyAndValue(key)) { - return true; - } - else { - if (dict.hasKeyAndValue(key)) { - // If we have a double value, we need to check if it is integer - double value = dict.value(key); - double intPart; - return modf(value, &intPart) == 0.0; - } - else { - // If we don't have a double value, we cannot have an int value - return false; - } - } - } + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string documentation() const override { - return "Type: Integer"; - } + std::string documentation() const override; }; struct StringVerifier : public TemplateVerifier { - bool test(const ghoul::Dictionary& dict, const std::string& key) const override { - return dict.hasKeyAndValue(key); - } + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string documentation() const override { - return "Type: String"; - } + std::string documentation() const override; }; struct TableVerifier : public TemplateVerifier { - TableVerifier(Documentation d) : doc(std::move(d)) {} + TableVerifier(Documentation d); - TestResult operator()(const ghoul::Dictionary& dict, const std::string& key) const override { - if (dict.hasKeyAndValue(key)) { - ghoul::Dictionary d = dict.value(key); - AbstractVerifier::TestResult res = testSpecification(doc, d); - - for (std::string& s : std::get<1>(res)) { - s = key + "." + s; - } + TestResult operator()(const ghoul::Dictionary& dict, const std::string& key) const override; - return res; - } - return{ dict.hasKeyAndValue(key), {} }; - } - - std::string documentation() const override { - return "Type: Table" + '\n' + generateDocumentation(doc); - } + std::string documentation() const override; Documentation doc; }; +// Operator Verifiers + template struct LessVerifier : public T { - LessVerifier(typename T::Type value) : value(std::move(value)) {} + LessVerifier(typename T::Type value); - bool test(const ghoul::Dictionary& dict, const std::string& key) const override { - return T::test(dict, key) && dict.value(key) < value; - } + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string documentation() const override { - return T::documentation() + '\n' + "Less than: " + std::to_string(value); - } + std::string documentation() const; typename T::Type value; }; template struct LessEqualVerifier : public T { - LessEqualVerifier(typename T::Type value) : value(std::move(value)) {} + LessEqualVerifier(typename T::Type value); - bool test(const ghoul::Dictionary& dict, const std::string& key) const override { - return T::test(dict, key) && dict.value(key) <= value; - } + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string documentation() const override { - return T::documentation() + '\n' + "Less or equal to: " + std::to_string(value); - } + std::string documentation() const override; typename T::Type value; }; template struct GreaterVerifier : public T { - GreaterVerifier(typename T::Type value) : value(std::move(value)) {} + GreaterVerifier(typename T::Type value); - bool test(const ghoul::Dictionary& dict, const std::string& key) const override { - return T::test(dict, key) && dict.value(key) > value; - } + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string documentation() const override { - return T::documentation() + '\n' + "Greater than: " + std::to_string(value); - } + std::string documentation() const override; typename T::Type value; }; template struct GreaterEqualVerifier : public T { - GreaterEqualVerifier(typename T::Type value) : value(std::move(value)) {} + GreaterEqualVerifier(typename T::Type value); - bool test(const ghoul::Dictionary& dict, const std::string& key) const override { - return T::test(dict, key) && dict.value(key) >= value; - } + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string documentation() const override { - return T::documentation() + '\n' + "Greater or equal to: " + std::to_string(value); - } + std::string documentation() const override; typename T::Type value; }; template struct EqualVerifier : public T { - EqualVerifier(typename T::Type value) : value(std::move(value)) {} + EqualVerifier(typename T::Type value); - bool test(const ghoul::Dictionary& dict, const std::string& key) const override { - return T::test(dict, key) && dict.value(key) == value; - } + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string documentation() const override { - return T::documentation() + '\n' + "Equal to: " + std::to_string(value); - } + std::string documentation() const override; typename T::Type value; }; template struct UnequalVerifier : public T { - UnequalVerifier(typename T::Type value) : value(std::move(value)) {} + UnequalVerifier(typename T::Type value); - bool test(const ghoul::Dictionary& dict, const std::string& key) const override { - return T::test(dict, key) && dict.value(key) != value; - } + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string documentation() const override { - return T::documentation() + '\n' + "Unequal to: " + std::to_string(value); - } + std::string documentation() const override; typename T::Type value; }; +// List Verifiers + template struct InListVerifier : public T { - InListVerifier(std::vector values) : values(std::move(values)) {} + InListVerifier(std::vector values); - bool test(const ghoul::Dictionary& dict, const std::string& key) const override { - if (T::test(dict, key)) { - typename T::Type value = dict.value(key); + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - auto it = std::find(values.begin(), values.end(), value); - return it != values.end(); - } - else { - return false; - } - } - - std::string documentation() const override { - std::string result = T::documentation() + '\n' + "In list {"; - - std::stringstream s; - std::copy(values.begin(), values.end(), std::ostream_iterator(s, ",")); - - std::string joined = s.str(); - // We need to remove a trailing ',' at the end of the string - result += joined.substr(0, joined.size() - 1); - - result += "}"; - return result; - } + std::string documentation() const override; std::vector values; }; template struct NotInListVerifier : public T { - NotInListVerifier(std::vector values) : values(std::move(values)) {} + NotInListVerifier(std::vector values); - bool test(const ghoul::Dictionary& dict, const std::string& key) const override { - if (T::test(dict, key)) { - typename T::Type value = dict.value(key); + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - auto it = std::find(values.begin(), values.end(), value); - return it == values.end(); - } - else { - return false; - } - } - - std::string documentation() const override { - std::string result = T::documentation() + '\n' + "Not in list {"; - - std::stringstream s; - std::copy(values.begin(), values.end(), std::ostream_iterator(s, ",")); - - std::string joined = s.str(); - // We need to remove a trailing ',' at the end of the string - result += joined.substr(0, joined.size() - 1); - - - result += "}"; - return result; - } + std::string documentation() const override; std::vector values; }; +// Misc Verifiers +template +struct AnnotationVerifier : public T { + AnnotationVerifier(std::string annotation); + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + std::string documentation() const override; + std::string annotation; +}; } // namespace documentation } // namespace openspace +#include "documentation.inl" + #endif // __DOCUMENTATION_H__ diff --git a/include/openspace/util/documentation.inl b/include/openspace/util/documentation.inl new file mode 100644 index 0000000000..4fbf6f40f1 --- /dev/null +++ b/include/openspace/util/documentation.inl @@ -0,0 +1,188 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +namespace openspace { +namespace documentation { + +template +LessVerifier::LessVerifier(typename T::Type value) : value(std::move(value)) {} + +template +bool LessVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { + return T::test(dict, key) && dict.value(key) < value; +} + +template +std::string LessVerifier::documentation() const { + return T::documentation() + '\n' + "Less than: " + std::to_string(value); +} + + +template +LessEqualVerifier::LessEqualVerifier(typename T::Type value) : value(std::move(value)) {} + +template +bool LessEqualVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { + return T::test(dict, key) && dict.value(key) <= value; +} + +template +std::string LessEqualVerifier::documentation() const { + return T::documentation() + '\n' + "Less or equal to: " + std::to_string(value); +} + +template +GreaterVerifier::GreaterVerifier(typename T::Type value) : value(std::move(value)) {} + +template +bool GreaterVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { + return T::test(dict, key) && dict.value(key) > value; +} + +template +std::string GreaterVerifier::documentation() const { + return T::documentation() + '\n' + "Greater than: " + std::to_string(value); +} + +template +GreaterEqualVerifier::GreaterEqualVerifier(typename T::Type value) : value(std::move(value)) {} + +template +bool GreaterEqualVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { + return T::test(dict, key) && dict.value(key) >= value; +} + +template +std::string GreaterEqualVerifier::documentation() const { + return T::documentation() + '\n' + "Greater or equal to: " + std::to_string(value); +} + +template +EqualVerifier::EqualVerifier(typename T::Type value) : value(std::move(value)) {} + +template +bool EqualVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { + return T::test(dict, key) && dict.value(key) == value; +} + +template +std::string EqualVerifier::documentation() const { + return T::documentation() + '\n' + "Equal to: " + std::to_string(value); +} + +template +UnequalVerifier::UnequalVerifier(typename T::Type value) : value(std::move(value)) {} + +template +bool UnequalVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { + return T::test(dict, key) && dict.value(key) != value; +} + +template +std::string UnequalVerifier::documentation() const override { + return T::documentation() + '\n' + "Unequal to: " + std::to_string(value); +} + +template +InListVerifier::InListVerifier(std::vector values) : values(std::move(values)) {} + +template +bool InListVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { + if (T::test(dict, key)) { + typename T::Type value = dict.value(key); + + auto it = std::find(values.begin(), values.end(), value); + return it != values.end(); + } + else { + return false; + } +} + +template +std::string InListVerifier::documentation() const { + std::string result = T::documentation() + '\n' + "In list {"; + + std::stringstream s; + std::copy(values.begin(), values.end(), std::ostream_iterator(s, ",")); + + std::string joined = s.str(); + // We need to remove a trailing ',' at the end of the string + result += joined.substr(0, joined.size() - 1); + + result += "}"; + return result; +} + +template +NotInListVerifier::NotInListVerifier(std::vector values) : values(std::move(values)) {} + +template +bool NotInListVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { + if (T::test(dict, key)) { + typename T::Type value = dict.value(key); + + auto it = std::find(values.begin(), values.end(), value); + return it == values.end(); + } + else { + return false; + } +} + +template +std::string NotInListVerifier::documentation() const { + std::string result = T::documentation() + '\n' + "Not in list {"; + + std::stringstream s; + std::copy(values.begin(), values.end(), std::ostream_iterator(s, ",")); + + std::string joined = s.str(); + // We need to remove a trailing ',' at the end of the string + result += joined.substr(0, joined.size() - 1); + + + result += "}"; + return result; +} + +template +AnnotationVerifier::AnnotationVerifier(std::string annotation) + : annotation(std::move(annotation)) +{} + +template +bool AnnotationVerifier::test(const ghoul::Dictionary& dict, + const std::string& key) const +{ + return T::test(dict, key); +} + +template +std::string AnnotationVerifier::documentation() const { + return T::documentation() + '\n' + annotation; +} + +} // namespace documentation +} // namespace openspace diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9b0a640699..c50e7a7561 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -86,6 +86,7 @@ set(OPENSPACE_SOURCE ${OPENSPACE_BASE_DIR}/src/util/blockplaneintersectiongeometry.cpp ${OPENSPACE_BASE_DIR}/src/util/boxgeometry.cpp ${OPENSPACE_BASE_DIR}/src/util/camera.cpp + ${OPENSPACE_BASE_DIR}/src/util/documentation.cpp ${OPENSPACE_BASE_DIR}/src/util/factorymanager.cpp ${OPENSPACE_BASE_DIR}/src/util/keys.cpp ${OPENSPACE_BASE_DIR}/src/util/openspacemodule.cpp @@ -173,6 +174,7 @@ set(OPENSPACE_HEADER ${OPENSPACE_BASE_DIR}/include/openspace/util/boxgeometry.h ${OPENSPACE_BASE_DIR}/include/openspace/util/camera.h ${OPENSPACE_BASE_DIR}/include/openspace/util/documentation.h + ${OPENSPACE_BASE_DIR}/include/openspace/util/documentation.inl ${OPENSPACE_BASE_DIR}/include/openspace/util/factorymanager.h ${OPENSPACE_BASE_DIR}/include/openspace/util/factorymanager.inl ${OPENSPACE_BASE_DIR}/include/openspace/util/keys.h diff --git a/src/util/documentation.cpp b/src/util/documentation.cpp new file mode 100644 index 0000000000..33e9f2b94c --- /dev/null +++ b/src/util/documentation.cpp @@ -0,0 +1,154 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +namespace openspace { +namespace documentation { + +TestResult Verifier::operator()(const ghoul::Dictionary& dict, + const std::string& key) const { + bool testSuccess = test(dict, key); + if (testSuccess) { + return{ testSuccess, {} }; + } + else { + return{ testSuccess, { key } }; + } +} + +bool Verifier::test(const ghoul::Dictionary& dict, const std::string& key) const { + return false; +}; + +DocumentationEntry::DocumentationEntry(std::string key, Verifier* t, + bool optional, std::string doc) + : key(std::move(key)) + , tester(std::move(t)) + , optional(optional) + , documentation(std::move(doc)) {} + +TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& dictionary) { + TestResult result; + result.success = true; + + for (const auto& p : d) { + Verifier& verifier = *(p.tester); + TestResult res = verifier(dictionary, p.key); + if (!res.success) { + result.success = false; + result.offenders.insert( + result.offenders.end(), + res.offenders.begin(), + res.offenders.end() + ); + } + } + return result; +} + +std::string generateDocumentation(const Documentation& d) { + using namespace std::string_literals; + std::string result; + + for (const auto& p : d) { + result += p.key + '\n'; + result += "Optional: "s + (p.optional ? "true" : "false") + '\n'; + result += p.tester->documentation() + '\n'; + result += '\n'; + result += p.documentation + '\n'; + } + + return result; +} + +bool BoolVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { + return dict.hasKeyAndValue(key); +} + +inline std::string BoolVerifier::documentation() const { + return "Type: Boolean"; +} + + +inline bool DoubleVerifier::test(const ghoul::Dictionary & dict, const std::string & key) const { + return dict.hasKeyAndValue(key); +} + +inline std::string DoubleVerifier::documentation() const { + return "Type: Double"; +} + +inline bool IntVerifier::test(const ghoul::Dictionary & dict, const std::string & key) const { + if (dict.hasKeyAndValue(key)) { + return true; + } + else { + if (dict.hasKeyAndValue(key)) { + // If we have a double value, we need to check if it is integer + double value = dict.value(key); + double intPart; + return modf(value, &intPart) == 0.0; + } + else { + // If we don't have a double value, we cannot have an int value + return false; + } + } +} + +inline std::string IntVerifier::documentation() const { + return "Type: Integer"; +} + +inline bool StringVerifier::test(const ghoul::Dictionary & dict, const std::string & key) const { + return dict.hasKeyAndValue(key); +} + +inline std::string StringVerifier::documentation() const { + return "Type: String"; +} + +inline TableVerifier::TableVerifier(Documentation d) : doc(std::move(d)) {} + +TestResult TableVerifier::operator()(const ghoul::Dictionary& dict, const std::string& key) const { + if (dict.hasKeyAndValue(key)) { + ghoul::Dictionary d = dict.value(key); + TestResult res = testSpecification(doc, d); + + for (std::string& s : res.offenders) { + s = key + "." + s; + } + + return res; + } + return{ dict.hasKeyAndValue(key),{} }; +} + +inline std::string TableVerifier::documentation() const { + return "Type: Table" + '\n' + generateDocumentation(doc); +} + +} // namespace documentation +} // namespace openspace From faf180ab7d58404c5b1c2fefb93076c327f01086 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Tue, 13 Sep 2016 19:29:00 +0200 Subject: [PATCH 37/92] Writing more Unit tests Add InRangeVerifier and NotInRangeVerifier Add static_asserts to prohibit nonsensical verifier combinations --- include/openspace/util/documentation.h | 60 +++++++++++++++- include/openspace/util/documentation.inl | 90 +++++++++++++++++++++--- src/util/documentation.cpp | 29 +++++--- 3 files changed, 158 insertions(+), 21 deletions(-) diff --git a/include/openspace/util/documentation.h b/include/openspace/util/documentation.h index ec06629316..a7fc690eb1 100644 --- a/include/openspace/util/documentation.h +++ b/include/openspace/util/documentation.h @@ -32,6 +32,7 @@ #include #include #include +#include #include namespace openspace { @@ -99,7 +100,7 @@ struct StringVerifier : public TemplateVerifier { }; struct TableVerifier : public TemplateVerifier { - TableVerifier(Documentation d); + TableVerifier(Documentation d = {}); TestResult operator()(const ghoul::Dictionary& dict, const std::string& key) const override; @@ -112,6 +113,10 @@ struct TableVerifier : public TemplateVerifier { template struct LessVerifier : public T { + static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); + static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); + static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + LessVerifier(typename T::Type value); bool test(const ghoul::Dictionary& dict, const std::string& key) const override; @@ -123,6 +128,10 @@ struct LessVerifier : public T { template struct LessEqualVerifier : public T { + static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); + static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); + static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + LessEqualVerifier(typename T::Type value); bool test(const ghoul::Dictionary& dict, const std::string& key) const override; @@ -134,6 +143,10 @@ struct LessEqualVerifier : public T { template struct GreaterVerifier : public T { + static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); + static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); + static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + GreaterVerifier(typename T::Type value); bool test(const ghoul::Dictionary& dict, const std::string& key) const override; @@ -145,6 +158,10 @@ struct GreaterVerifier : public T { template struct GreaterEqualVerifier : public T { + static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); + static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); + static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + GreaterEqualVerifier(typename T::Type value); bool test(const ghoul::Dictionary& dict, const std::string& key) const override; @@ -156,6 +173,8 @@ struct GreaterEqualVerifier : public T { template struct EqualVerifier : public T { + static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + EqualVerifier(typename T::Type value); bool test(const ghoul::Dictionary& dict, const std::string& key) const override; @@ -167,6 +186,8 @@ struct EqualVerifier : public T { template struct UnequalVerifier : public T { + static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + UnequalVerifier(typename T::Type value); bool test(const ghoul::Dictionary& dict, const std::string& key) const override; @@ -180,6 +201,8 @@ struct UnequalVerifier : public T { template struct InListVerifier : public T { + static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + InListVerifier(std::vector values); bool test(const ghoul::Dictionary& dict, const std::string& key) const override; @@ -191,6 +214,8 @@ struct InListVerifier : public T { template struct NotInListVerifier : public T { + static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + NotInListVerifier(std::vector values); bool test(const ghoul::Dictionary& dict, const std::string& key) const override; @@ -200,6 +225,39 @@ struct NotInListVerifier : public T { std::vector values; }; +// Range Verifiers +template +struct InRangeVerifier : public T { + static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); + static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); + static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + + InRangeVerifier(typename T::Type lower, typename T::Type upper); + + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + + std::string documentation() const override; + + typename T::Type lower; + typename T::Type upper; +}; + +template +struct NotInRangeVerifier : public T { + static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); + static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); + static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + + NotInRangeVerifier(typename T::Type lower, typename T::Type upper); + + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + + std::string documentation() const override; + + typename T::Type lower; + typename T::Type upper; +}; + // Misc Verifiers template diff --git a/include/openspace/util/documentation.inl b/include/openspace/util/documentation.inl index 4fbf6f40f1..ad741cfe93 100644 --- a/include/openspace/util/documentation.inl +++ b/include/openspace/util/documentation.inl @@ -22,11 +22,18 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ +namespace std { +std::string to_string(std::string value); +} + namespace openspace { namespace documentation { template -LessVerifier::LessVerifier(typename T::Type value) : value(std::move(value)) {} +LessVerifier::LessVerifier(typename T::Type value) + : value(std::move(value)) +{ +} template bool LessVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { @@ -40,7 +47,9 @@ std::string LessVerifier::documentation() const { template -LessEqualVerifier::LessEqualVerifier(typename T::Type value) : value(std::move(value)) {} +LessEqualVerifier::LessEqualVerifier(typename T::Type value) + : value(std::move(value)) +{} template bool LessEqualVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { @@ -53,7 +62,9 @@ std::string LessEqualVerifier::documentation() const { } template -GreaterVerifier::GreaterVerifier(typename T::Type value) : value(std::move(value)) {} +GreaterVerifier::GreaterVerifier(typename T::Type value) + : value(std::move(value)) +{} template bool GreaterVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { @@ -66,7 +77,9 @@ std::string GreaterVerifier::documentation() const { } template -GreaterEqualVerifier::GreaterEqualVerifier(typename T::Type value) : value(std::move(value)) {} +GreaterEqualVerifier::GreaterEqualVerifier(typename T::Type value) + : value(std::move(value)) +{} template bool GreaterEqualVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { @@ -79,7 +92,9 @@ std::string GreaterEqualVerifier::documentation() const { } template -EqualVerifier::EqualVerifier(typename T::Type value) : value(std::move(value)) {} +EqualVerifier::EqualVerifier(typename T::Type value) + : value(std::move(value)) +{} template bool EqualVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { @@ -92,7 +107,9 @@ std::string EqualVerifier::documentation() const { } template -UnequalVerifier::UnequalVerifier(typename T::Type value) : value(std::move(value)) {} +UnequalVerifier::UnequalVerifier(typename T::Type value) + : value(std::move(value)) +{} template bool UnequalVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { @@ -100,12 +117,14 @@ bool UnequalVerifier::test(const ghoul::Dictionary& dict, const std::string& } template -std::string UnequalVerifier::documentation() const override { +std::string UnequalVerifier::documentation() const { return T::documentation() + '\n' + "Unequal to: " + std::to_string(value); } template -InListVerifier::InListVerifier(std::vector values) : values(std::move(values)) {} +InListVerifier::InListVerifier(std::vector values) + : values(std::move(values)) +{} template bool InListVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { @@ -136,7 +155,9 @@ std::string InListVerifier::documentation() const { } template -NotInListVerifier::NotInListVerifier(std::vector values) : values(std::move(values)) {} +NotInListVerifier::NotInListVerifier(std::vector values) + : values(std::move(values)) +{} template bool NotInListVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { @@ -167,6 +188,57 @@ std::string NotInListVerifier::documentation() const { return result; } +template +InRangeVerifier::InRangeVerifier(typename T::Type lower, typename T::Type upper) + : lower(std::move(lower)) + , upper(std::move(upper)) +{ + ghoul_assert(lower <= upper, "Lower value must be smaller or equal to upper value"); +} + +template +bool InRangeVerifier::test(const ghoul::Dictionary& d, const std::string& key) const { + if (T::test(d, key)) { + typename T::Type val = d.value(key); + return val >= lower && val <= upper; + } + else { + return false; + } +} + +template +std::string InRangeVerifier::documentation() const { + return T::documentation() + '\n' + "In range: (" + std::to_string(lower) + "," + + std::to_string(upper) + ")"; +} + +template +NotInRangeVerifier::NotInRangeVerifier(typename T::Type lower, typename T::Type upper) + : lower(std::move(lower)) + , upper(std::move(upper)) +{ + ghoul_assert(lower <= upper, "Lower value must be smaller or equal to upper value"); +} + +template +bool NotInRangeVerifier::test(const ghoul::Dictionary& d, const std::string& k) const { + if (T::test(d, k)) { + typename T::Type val = d.value(k); + return !(val >= lower && val <= upper); + } + else { + return false; + } +} + +template +std::string NotInRangeVerifier::documentation() const { + return T::documentation() + '\n' + "Not in range: (" + std::to_string(lower) + "," + + std::to_string(upper) + ")"; +} + + template AnnotationVerifier::AnnotationVerifier(std::string annotation) : annotation(std::move(annotation)) diff --git a/src/util/documentation.cpp b/src/util/documentation.cpp index 33e9f2b94c..84a31fb525 100644 --- a/src/util/documentation.cpp +++ b/src/util/documentation.cpp @@ -24,6 +24,12 @@ #include +namespace std { +std::string to_string(std::string value) { + return value; +} +} // namespace std + namespace openspace { namespace documentation { @@ -87,20 +93,19 @@ bool BoolVerifier::test(const ghoul::Dictionary& dict, const std::string& key) c return dict.hasKeyAndValue(key); } -inline std::string BoolVerifier::documentation() const { +std::string BoolVerifier::documentation() const { return "Type: Boolean"; } - -inline bool DoubleVerifier::test(const ghoul::Dictionary & dict, const std::string & key) const { +bool DoubleVerifier::test(const ghoul::Dictionary & dict, const std::string & key) const { return dict.hasKeyAndValue(key); } -inline std::string DoubleVerifier::documentation() const { +std::string DoubleVerifier::documentation() const { return "Type: Double"; } -inline bool IntVerifier::test(const ghoul::Dictionary & dict, const std::string & key) const { +bool IntVerifier::test(const ghoul::Dictionary & dict, const std::string & key) const { if (dict.hasKeyAndValue(key)) { return true; } @@ -118,19 +123,21 @@ inline bool IntVerifier::test(const ghoul::Dictionary & dict, const std::string } } -inline std::string IntVerifier::documentation() const { +std::string IntVerifier::documentation() const { return "Type: Integer"; } -inline bool StringVerifier::test(const ghoul::Dictionary & dict, const std::string & key) const { +bool StringVerifier::test(const ghoul::Dictionary & dict, const std::string & key) const { return dict.hasKeyAndValue(key); } -inline std::string StringVerifier::documentation() const { +std::string StringVerifier::documentation() const { return "Type: String"; } -inline TableVerifier::TableVerifier(Documentation d) : doc(std::move(d)) {} +TableVerifier::TableVerifier(Documentation d) + : doc(std::move(d)) +{} TestResult TableVerifier::operator()(const ghoul::Dictionary& dict, const std::string& key) const { if (dict.hasKeyAndValue(key)) { @@ -143,10 +150,10 @@ TestResult TableVerifier::operator()(const ghoul::Dictionary& dict, const std::s return res; } - return{ dict.hasKeyAndValue(key),{} }; + return{ dict.hasKeyAndValue(key), { key } }; } -inline std::string TableVerifier::documentation() const { +std::string TableVerifier::documentation() const { return "Type: Table" + '\n' + generateDocumentation(doc); } From 2e355c57e74e510f3176b53f64c7b31aea91f6ec Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Tue, 13 Sep 2016 19:35:33 +0200 Subject: [PATCH 38/92] Add external template instantiation --- include/openspace/util/documentation.h | 31 ++++++++++++++++++++++++++ src/util/documentation.cpp | 31 ++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/include/openspace/util/documentation.h b/include/openspace/util/documentation.h index a7fc690eb1..8b479a09ae 100644 --- a/include/openspace/util/documentation.h +++ b/include/openspace/util/documentation.h @@ -271,6 +271,37 @@ struct AnnotationVerifier : public T { std::string annotation; }; +extern template struct LessVerifier; +extern template struct LessVerifier; +extern template struct LessEqualVerifier; +extern template struct LessEqualVerifier; +extern template struct GreaterVerifier; +extern template struct GreaterVerifier; +extern template struct GreaterEqualVerifier; +extern template struct GreaterEqualVerifier; +extern template struct EqualVerifier; +extern template struct EqualVerifier; +extern template struct EqualVerifier; +extern template struct EqualVerifier; +extern template struct UnequalVerifier; +extern template struct UnequalVerifier; +extern template struct UnequalVerifier; +extern template struct UnequalVerifier; + +extern template struct InListVerifier; +extern template struct InListVerifier; +extern template struct InListVerifier; +extern template struct InListVerifier; +extern template struct NotInListVerifier; +extern template struct NotInListVerifier; +extern template struct NotInListVerifier; +extern template struct NotInListVerifier; + +extern template struct InRangeVerifier; +extern template struct InRangeVerifier; +extern template struct NotInRangeVerifier; +extern template struct NotInRangeVerifier; + } // namespace documentation } // namespace openspace diff --git a/src/util/documentation.cpp b/src/util/documentation.cpp index 84a31fb525..ac525aa762 100644 --- a/src/util/documentation.cpp +++ b/src/util/documentation.cpp @@ -33,6 +33,37 @@ std::string to_string(std::string value) { namespace openspace { namespace documentation { +template struct LessVerifier; +template struct LessVerifier; +template struct LessEqualVerifier; +template struct LessEqualVerifier; +template struct GreaterVerifier; +template struct GreaterVerifier; +template struct GreaterEqualVerifier; +template struct GreaterEqualVerifier; +template struct EqualVerifier; +template struct EqualVerifier; +template struct EqualVerifier; +template struct EqualVerifier; +template struct UnequalVerifier; +template struct UnequalVerifier; +template struct UnequalVerifier; +template struct UnequalVerifier; + +template struct InListVerifier; +template struct InListVerifier; +template struct InListVerifier; +template struct InListVerifier; +template struct NotInListVerifier; +template struct NotInListVerifier; +template struct NotInListVerifier; +template struct NotInListVerifier; + +template struct InRangeVerifier; +template struct InRangeVerifier; +template struct NotInRangeVerifier; +template struct NotInRangeVerifier; + TestResult Verifier::operator()(const ghoul::Dictionary& dict, const std::string& key) const { bool testSuccess = test(dict, key); From a71cccd58f7867b01a20dd1103c4a72a91adea22 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Tue, 13 Sep 2016 19:58:58 +0200 Subject: [PATCH 39/92] Adding unit tests file Adding typedefs for all verifiers --- include/openspace/util/documentation.h | 44 + src/util/documentation.cpp | 7 + tests/test_documentation.inl | 1444 ++++++++++++++++++++++++ 3 files changed, 1495 insertions(+) create mode 100644 tests/test_documentation.inl diff --git a/include/openspace/util/documentation.h b/include/openspace/util/documentation.h index 8b479a09ae..a049e785cc 100644 --- a/include/openspace/util/documentation.h +++ b/include/openspace/util/documentation.h @@ -271,6 +271,44 @@ struct AnnotationVerifier : public T { std::string annotation; }; +using IntLessVerifier = LessVerifier; +using DoubleLessVerifier = LessVerifier; +using IntLessEqualVerifier = LessEqualVerifier; +using DoubleLessEqualVerifier = LessEqualVerifier; +using IntGreaterVerifier = GreaterVerifier; +using DoubleGreaterVerifier = GreaterVerifier; +using IntGreaterEqualVerifier = GreaterEqualVerifier; +using DoubleGreaterEqualVerifier = GreaterEqualVerifier; +using BoolEqualVerifier = EqualVerifier; +using IntEqualVerifier = EqualVerifier; +using DoubleEqualVerifier = EqualVerifier; +using StringEqualVerifier = EqualVerifier; +using BoolUnequalVerifier = UnequalVerifier; +using IntUnequalVerifier = UnequalVerifier; +using DoubleUnequalVerifier = UnequalVerifier; +using StringUnequalVerifier = UnequalVerifier; + +using BoolInListVerifier = InListVerifier; +using IntInListVerifier = InListVerifier; +using DoubleInListVerifier = InListVerifier; +using StringInListVerifier = InListVerifier; +using BoolNotInListVerifier = NotInListVerifier; +using IntNotInListVerifier = NotInListVerifier; +using DoubleNotInListVerifier = NotInListVerifier; +using StringNotInListVerifier = NotInListVerifier; + +using IntInRangeVerifier = InRangeVerifier; +using DoubleInRangeVerifier = InRangeVerifier; +using IntNotInRangeVerifier = NotInRangeVerifier; +using DoubleNotInRangeVerifier = NotInRangeVerifier; + +using BoolAnnotationVerifier = AnnotationVerifier; +using IntAnnotationVerifier = AnnotationVerifier; +using DoubleAnnotationVerifier = AnnotationVerifier; +using StringAnnotationVerifier = AnnotationVerifier; +using TableAnnotationVerifier = AnnotationVerifier; + + extern template struct LessVerifier; extern template struct LessVerifier; extern template struct LessEqualVerifier; @@ -302,6 +340,12 @@ extern template struct InRangeVerifier; extern template struct NotInRangeVerifier; extern template struct NotInRangeVerifier; +extern template struct AnnotationVerifier; +extern template struct AnnotationVerifier; +extern template struct AnnotationVerifier; +extern template struct AnnotationVerifier; +extern template struct AnnotationVerifier; + } // namespace documentation } // namespace openspace diff --git a/src/util/documentation.cpp b/src/util/documentation.cpp index ac525aa762..c4fd5ca8a6 100644 --- a/src/util/documentation.cpp +++ b/src/util/documentation.cpp @@ -64,6 +64,13 @@ template struct InRangeVerifier; template struct NotInRangeVerifier; template struct NotInRangeVerifier; +template struct AnnotationVerifier; +template struct AnnotationVerifier; +template struct AnnotationVerifier; +template struct AnnotationVerifier; +template struct AnnotationVerifier; + + TestResult Verifier::operator()(const ghoul::Dictionary& dict, const std::string& key) const { bool testSuccess = test(dict, key); diff --git a/tests/test_documentation.inl b/tests/test_documentation.inl new file mode 100644 index 0000000000..ea48200ef1 --- /dev/null +++ b/tests/test_documentation.inl @@ -0,0 +1,1444 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include "gtest/gtest.h" + +#include + +#include + +#include + +/* + * To test: + * optional values + * + * to add: + * external template instantiations +*/ + +class DocumentationTest : public testing::Test {}; + +TEST_F(DocumentationTest, Constructor) { + using namespace openspace::documentation; + + Documentation doc; + + // Basic Verifiers + doc.emplace_back("BoolVerifier", new BoolVerifier); + doc.emplace_back("DoubleVerifier", new DoubleVerifier); + doc.emplace_back("IntVerifier", new IntVerifier); + doc.emplace_back("StringVerifier", new StringVerifier); + doc.emplace_back("TableVerifier", new TableVerifier); + + // Operator Verifiers + doc.emplace_back("LessDouble", new DoubleLessVerifier(0.0)); + doc.emplace_back("LessInt", new IntLessVerifier(0)); + + doc.emplace_back("LessEqualDouble", new DoubleLessEqualVerifier(0.0)); + doc.emplace_back("LessEqualInt", new IntLessEqualVerifier(0)); + + doc.emplace_back("GreaterDouble", new DoubleGreaterVerifier(0.0)); + doc.emplace_back("GreaterInt", new IntGreaterVerifier(0)); + + doc.emplace_back("GreaterEqualDouble", new DoubleGreaterEqualVerifier(0.0)); + doc.emplace_back("GreaterEqualInt", new IntGreaterEqualVerifier(0)); + + doc.emplace_back("EqualBool", new BoolEqualVerifier(false)); + doc.emplace_back("EqualDouble", new DoubleEqualVerifier(0.0)); + doc.emplace_back("EqualInt", new IntEqualVerifier(0)); + doc.emplace_back("EqualString", new StringEqualVerifier("")); + + doc.emplace_back("UnequalBool", new BoolUnequalVerifier(false)); + doc.emplace_back("UnequalDouble", new DoubleUnequalVerifier(0.0)); + doc.emplace_back("UnequalInt", new IntUnequalVerifier(0)); + doc.emplace_back("UnequalString", new StringUnequalVerifier("")); + + // List Verifiers + doc.emplace_back("InListBool", new BoolInListVerifier({ true, false })); + doc.emplace_back("InListDouble", new DoubleInListVerifier({ 0.0, 1.0})); + doc.emplace_back("InListInt", new IntInListVerifier({ 0, 1 })); + doc.emplace_back("InListString", new StringInListVerifier({ "", "a" })); + + doc.emplace_back("NotInListBool", new BoolNotInListVerifier({ true, false })); + doc.emplace_back("NotInListDouble", new DoubleNotInListVerifier({ 0.0, 1.0 })); + doc.emplace_back("NotInListInt", new IntNotInListVerifier({ 0, 1 })); + doc.emplace_back("NotInListString", new StringNotInListVerifier({ "", "a" })); + + // Misc Verifiers + doc.emplace_back("AnnotationBool", new BoolAnnotationVerifier("Bool")); + doc.emplace_back("AnnotationDouble", new DoubleAnnotationVerifier("Double")); + doc.emplace_back("AnnotationInt", new IntAnnotationVerifier("Int")); + doc.emplace_back("AnnotationString", new StringAnnotationVerifier("String")); + doc.emplace_back("AnnotationTable", new TableAnnotationVerifier("Table")); +} + +TEST_F(DocumentationTest, InitializerConstructor) { + using namespace openspace::documentation; + + Documentation doc{ + // Basic Verifiers + {"BoolVerifier", new BoolVerifier }, + {"DoubleVerifier", new DoubleVerifier}, + {"IntVerifier", new IntVerifier}, + {"StringVerifier", new StringVerifier}, + {"TableVerifier", new TableVerifier}, + + // Operator Verifiers + { "LessDouble", new DoubleLessVerifier(0.0)}, + { "LessInt", new IntLessVerifier(0)}, + + {"LessEqualDouble", new DoubleLessEqualVerifier(0.0)}, + {"LessEqualInt", new IntLessEqualVerifier(0)}, + + {"GreaterDouble", new DoubleGreaterVerifier(0.0)}, + {"GreaterInt", new IntGreaterVerifier(0)}, + + {"GreaterEqualDouble", new DoubleGreaterEqualVerifier(0.0)}, + {"GreaterEqualInt", new IntGreaterEqualVerifier(0)}, + + {"EqualBool", new BoolEqualVerifier(false)}, + {"EqualDouble", new DoubleEqualVerifier(0.0)}, + {"EqualInt", new IntEqualVerifier(0)}, + {"EqualString", new StringEqualVerifier("")}, + + {"UnequalBool", new BoolUnequalVerifier(false)}, + {"UnequalDouble", new DoubleUnequalVerifier(0.0)}, + {"UnequalInt", new IntUnequalVerifier(0)}, + {"UnequalString", new StringUnequalVerifier("")}, + + // List Verifiers + {"InListBool", new BoolInListVerifier({ true, false })}, + {"InListDouble", new DoubleInListVerifier({ 0.0, 1.0 })}, + {"InListInt", new IntInListVerifier({ 0, 1 })}, + {"InListString", new StringInListVerifier({ "", "a" })}, + + {"NotInListBool", new BoolNotInListVerifier({ true, false })}, + {"NotInListDouble", new DoubleNotInListVerifier({ 0.0, 1.0 })}, + {"NotInListInt", new IntNotInListVerifier({ 0, 1 })}, + {"NotInListString", new StringNotInListVerifier({ "", "a" })}, + + // Misc Verifiers + {"AnnotationBool", new BoolAnnotationVerifier("Bool")}, + {"AnnotationDouble", new DoubleAnnotationVerifier("Double")}, + {"AnnotationInt", new IntAnnotationVerifier("Int")}, + {"AnnotationString", new StringAnnotationVerifier("String")}, + {"AnnotationTable", new TableAnnotationVerifier("Table")} + }; +} + +TEST_F(DocumentationTest, BoolVerifier) { + using namespace openspace::documentation; + + Documentation doc{ + { "Bool", new BoolVerifier }, + }; + + ghoul::Dictionary positive { + { "Bool", true } + }; + + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Bool", 0} + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Bool", negativeRes.offenders[0]); + + ghoul::Dictionary negativeExist { + { "Bool2", 0} + }; + negativeRes = testSpecification(doc, negativeExist); + + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Bool", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, DoubleVerifier) { + using namespace openspace::documentation; + + Documentation doc { + { "Double", new DoubleVerifier } + }; + + ghoul::Dictionary positive { + { "Double", 0.0 } + }; + + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Double", 0 } + }; + + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Double", negativeRes.offenders[0]); + + ghoul::Dictionary negativeExist{ + { "Double2" , 0.0 } + }; + negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Double", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, IntVerifier) { + using namespace openspace::documentation; + + Documentation doc { + { "Int", new IntVerifier } + }; + + ghoul::Dictionary positive { + { "Int", 0 } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary positive2 { + { "Int", 0.0 } + }; + positiveRes = testSpecification(doc, positive2); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Int", 0.1 } + }; + + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Int", negativeRes.offenders[0]); + + ghoul::Dictionary negativeExist{ + { "Int2", 0 } + }; + negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Int", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, StringVerifier) { + using namespace openspace::documentation; + using namespace std::string_literals; + + Documentation doc { + { "String", new StringVerifier } + }; + + ghoul::Dictionary positive { + { "String", ""s } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "String", 0 } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("String", negativeRes.offenders[0]); + + ghoul::Dictionary negativeExist{ + { "String2", ""s } + }; + negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("String", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, TableVerifierType) { + using namespace openspace::documentation; + + Documentation doc { + { "Table", new TableVerifier } + }; + + ghoul::Dictionary positive { + { "Table", ghoul::Dictionary{} } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Table", 0 } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Table", negativeRes.offenders[0]); + + ghoul::Dictionary negativeExist { + { "Table2", ghoul::Dictionary{} } + }; + negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Table", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, MixedVerifiers) { + using namespace openspace::documentation; + using namespace std::string_literals; + + Documentation doc { + { "Bool", new BoolVerifier }, + { "Double", new DoubleVerifier }, + { "Int", new IntVerifier }, + { "String", new StringVerifier }, + { "Table", new TableVerifier } + }; + + ghoul::Dictionary positive { + { "Bool", true }, + { "Double", 0.0 }, + { "Int", 0 }, + { "String", ""s }, + { "Table", ghoul::Dictionary{} } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative1 { + { "Bool", true }, + { "Double", 1 }, + { "Int", 0 }, + { "String", ""s }, + { "Table", ghoul::Dictionary{} } + }; + TestResult negativeRes = testSpecification(doc, negative1); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Double", negativeRes.offenders[0]); + + ghoul::Dictionary negative2 { + { "Bool", true }, + { "Double", 0.0 }, + { "Int", ""s }, + { "String", 1 }, + { "Table", ghoul::Dictionary{} } + }; + negativeRes = testSpecification(doc, negative2); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(2, negativeRes.offenders.size()); + EXPECT_EQ("Int", negativeRes.offenders[0]); + EXPECT_EQ("String", negativeRes.offenders[1]); +} + +TEST_F(DocumentationTest, NestedTables) { + using namespace openspace::documentation; + using namespace std::string_literals; + + Documentation doc { + { "Outer_Int", new IntVerifier }, + { "Outer_Table", new TableVerifier({ + { "Inner_Double", new DoubleVerifier }, + { "Inner_String", new StringVerifier } + })}, + { "Outer_Double", new DoubleVerifier }, + { "Outer_Table2" , new TableVerifier({ + { "Inner_Double2", new DoubleVerifier }, + { "Inner_String2", new StringVerifier }, + { "Inner_Table" , new TableVerifier({ + { "Inner_Inner_Int", new IntVerifier } + })} + })} + }; + + ghoul::Dictionary positive { + { "Outer_Int", 1 }, + { "Outer_Table", ghoul::Dictionary { + { "Inner_Double", 0.0 }, + { "Inner_String", ""s } + }}, + { "Outer_Double", 0.0 }, + { "Outer_Table2", ghoul::Dictionary { + { "Inner_Double2", 0.0 }, + { "Inner_String2", ""s }, + { "Inner_Table", ghoul::Dictionary { + { "Inner_Inner_Int", 0 } + }} + }} + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negativeSimple { + { "Outer_Int", 1 }, + { "Outer_Table", 0}, + { "Outer_Double", 0.0 }, + { "Outer_Table2", ghoul::Dictionary { + { "Inner_Double2", 0.0 }, + { "Inner_String2", ""s }, + { "Inner_Table", ghoul::Dictionary { + { "Inner_Inner_Int", 0 } + }} + }} + }; + TestResult negativeRes = testSpecification(doc, negativeSimple); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Outer_Table", negativeRes.offenders[0]); + + ghoul::Dictionary negativeInner { + { "Outer_Int", 1 }, + { "Outer_Table", ghoul::Dictionary { + { "Inner_Double", ""s }, + { "Inner_String", ""s } + }}, + { "Outer_Double", 0.0 }, + { "Outer_Table2", ghoul::Dictionary { + { "Inner_Double2", 0.0 }, + { "Inner_String2", ""s }, + { "Inner_Table", ghoul::Dictionary { + { "Inner_Inner_Int", 0 } + }} + }} + }; + negativeRes = testSpecification(doc, negativeInner); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Outer_Table.Inner_Double", negativeRes.offenders[0]); + + ghoul::Dictionary negativeInner2 { + { "Outer_Int", 1 }, + { "Outer_Table", ghoul::Dictionary { + { "Inner_Double", ""s }, + { "Inner_String", 0.0 } + }}, + { "Outer_Double", 0.0 }, + { "Outer_Table2", ghoul::Dictionary { + { "Inner_Double2", 0.0 }, + { "Inner_String2", ""s }, + { "Inner_Table", ghoul::Dictionary { + { "Inner_Inner_Int", 0 } + }} + }} + }; + negativeRes = testSpecification(doc, negativeInner2); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(2, negativeRes.offenders.size()); + EXPECT_EQ("Outer_Table.Inner_Double", negativeRes.offenders[0]); + EXPECT_EQ("Outer_Table.Inner_String", negativeRes.offenders[1]); + + ghoul::Dictionary negativeInnerSeparate { + { "Outer_Int", 1 }, + { "Outer_Table", ghoul::Dictionary { + { "Inner_Double", ""s }, + { "Inner_String", ""s } + } }, + { "Outer_Double", 0.0 }, + { "Outer_Table2", ghoul::Dictionary { + { "Inner_Double2", ""s }, + { "Inner_String2", ""s }, + { "Inner_Table", ghoul::Dictionary { + { "Inner_Inner_Int", 0 } + }} + }} + }; + negativeRes = testSpecification(doc, negativeInnerSeparate); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(2, negativeRes.offenders.size()); + EXPECT_EQ("Outer_Table.Inner_Double", negativeRes.offenders[0]); + EXPECT_EQ("Outer_Table2.Inner_Double2", negativeRes.offenders[1]); + + ghoul::Dictionary negativeInnerFull { + { "Outer_Int", 1 }, + { "Outer_Table", ghoul::Dictionary { + { "Inner_Double", ""s }, + { "Inner_String", ""s } + } }, + { "Outer_Double", 0.0 }, + { "Outer_Table2", ghoul::Dictionary { + { "Inner_Double2", ""s }, + { "Inner_String2", ""s }, + { "Inner_Table", ghoul::Dictionary { + { "Inner_Inner_Int", ""s } + }} + }} + }; + negativeRes = testSpecification(doc, negativeInnerFull); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(3, negativeRes.offenders.size()); + EXPECT_EQ("Outer_Table.Inner_Double", negativeRes.offenders[0]); + EXPECT_EQ("Outer_Table2.Inner_Double2", negativeRes.offenders[1]); + EXPECT_EQ("Outer_Table2.Inner_Table.Inner_Inner_Int", negativeRes.offenders[2]); +} + +TEST_F(DocumentationTest, LessInt) { + using namespace openspace::documentation; + + Documentation doc { + { "Int", new IntLessVerifier(5) } + }; + + ghoul::Dictionary positive { + { "Int", 0 } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Int", 10 } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Int", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, LessDouble) { + using namespace openspace::documentation; + + Documentation doc { + { "Double", new DoubleLessVerifier(5.0) } + }; + + ghoul::Dictionary positive { + { "Double", 0.0 } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Double", 10.0 } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Double", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, LessEqualInt) { + using namespace openspace::documentation; + + Documentation doc { + { "Int", new IntLessEqualVerifier(5) } + }; + + ghoul::Dictionary positive { + { "Int", 0 } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary positiveEqual { + { "Int", 5 } + }; + positiveRes = testSpecification(doc, positiveEqual); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Int", 10 } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Int", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, LessEqualDouble) { + using namespace openspace::documentation; + + Documentation doc { + { "Double", new DoubleLessEqualVerifier(5.0) } + }; + + ghoul::Dictionary positive { + { "Double", 0.0 } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary positiveEqual { + { "Double", 5.0 } + }; + positiveRes = testSpecification(doc, positiveEqual); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Double", 10.0 } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Double", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, GreaterInt) { + using namespace openspace::documentation; + + Documentation doc { + { "Int", new IntGreaterVerifier(5) } + }; + + ghoul::Dictionary positive { + { "Int", 10 } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Int", 00 } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Int", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, GreaterDouble) { + using namespace openspace::documentation; + + Documentation doc { + { "Double", new DoubleGreaterVerifier(5.0) } + }; + + ghoul::Dictionary positive { + { "Double", 10.0 } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Double", 0.0 } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Double", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, GreaterEqualInt) { + using namespace openspace::documentation; + + Documentation doc { + { "Int", new IntGreaterEqualVerifier(5) } + }; + + ghoul::Dictionary positive { + { "Int", 10 } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary positiveEqual { + { "Int", 5 } + }; + positiveRes = testSpecification(doc, positiveEqual); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Int", 0 } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Int", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, GreaterEqualDouble) { + using namespace openspace::documentation; + + Documentation doc { + { "Double", new DoubleGreaterEqualVerifier(5.0) } + }; + + ghoul::Dictionary positive { + { "Double", 10.0 } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary positiveEqual { + { "Double", 5.0 } + }; + positiveRes = testSpecification(doc, positiveEqual); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Double", 0.0 } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Double", negativeRes.offenders[0]); +} + + +TEST_F(DocumentationTest, EqualBool) { + using namespace openspace::documentation; + + Documentation doc { + { "Bool", new BoolEqualVerifier(true) } + }; + + ghoul::Dictionary positive { + { "Bool", true} + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Bool", false } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Bool", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, EqualInt) { + using namespace openspace::documentation; + + Documentation doc { + { "Int", new IntEqualVerifier(1) } + }; + + ghoul::Dictionary positive { + { "Int", 1} + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Int", 0 } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Int", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, EqualDouble) { + using namespace openspace::documentation; + + Documentation doc { + { "Double", new DoubleEqualVerifier(1.0) } + }; + + ghoul::Dictionary positive { + { "Double", 1.0 } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Double", 0.0 } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Double", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, EqualString) { + using namespace openspace::documentation; + using namespace std::string_literals; + + Documentation doc { + { "String", new StringEqualVerifier("string"s) } + }; + + ghoul::Dictionary positive { + { "String", "string"s } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "String", "no_string"s } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("String", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, UnequalBool) { + using namespace openspace::documentation; + + Documentation doc { + { "Bool", new BoolUnequalVerifier(true) } + }; + + ghoul::Dictionary positive { + { "Bool", false } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Bool", true } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Bool", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, UnequalInt) { + using namespace openspace::documentation; + + Documentation doc { + { "Int", new IntUnequalVerifier(1) } + }; + + ghoul::Dictionary positive { + { "Int", 0 } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Int", 1 } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Int", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, UnequalDouble) { + using namespace openspace::documentation; + + Documentation doc { + { "Double", new DoubleUnequalVerifier(1.0) } + }; + + ghoul::Dictionary positive { + { "Double", 0.0 } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Double", 1.0 } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Double", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, UnequalString) { + using namespace openspace::documentation; + using namespace std::string_literals; + + Documentation doc { + { "String", new StringUnequalVerifier("string"s) } + }; + + ghoul::Dictionary positive { + { "String", "no_string"s } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "String", "string"s } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("String", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, ListBool) { + using namespace openspace::documentation; + + Documentation doc { + { "Bool" , new BoolInListVerifier({ true }) } + }; + + ghoul::Dictionary positive { + { "Bool", true } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Bool", false } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Bool", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, ListInt) { + using namespace openspace::documentation; + + Documentation doc { + { "Int" , new IntInListVerifier({ 0, 1, 2 }) } + }; + + ghoul::Dictionary positive { + { "Int", 1 } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary positive2 { + { "Int", 2 } + }; + positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Int", 5 } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Int", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, ListDouble) { + using namespace openspace::documentation; + + Documentation doc { + { "Double" , new DoubleInListVerifier({ 0.0, 1.0, 2.0 }) } + }; + + ghoul::Dictionary positive { + { "Double", 1.0 } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary positive2 { + { "Double", 2.0 } + }; + positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Double", 5.0 } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Double", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, ListString) { + using namespace openspace::documentation; + using namespace std::string_literals; + + Documentation doc { + { "String" , new StringInListVerifier({ "0"s, "1"s, "2"s }) } + }; + + ghoul::Dictionary positive { + { "String", "1"s } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary positive2 { + { "String", "2"s } + }; + positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "String", "5"s } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("String", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, NotListBool) { + using namespace openspace::documentation; + + Documentation doc { + { "Bool" , new BoolNotInListVerifier({ true }) } + }; + + ghoul::Dictionary positive { + { "Bool", false } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Bool", true } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Bool", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, NotListInt) { + using namespace openspace::documentation; + + Documentation doc { + { "Int" , new IntNotInListVerifier({ 0, 1, 2 }) } + }; + + ghoul::Dictionary positive { + { "Int", -1 } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary positive2 { + { "Int", 3 } + }; + positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Int", 2 } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Int", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, NotListDouble) { + using namespace openspace::documentation; + + Documentation doc { + { "Double" , new DoubleNotInListVerifier({ 0.0, 1.0, 2.0 }) } + }; + + ghoul::Dictionary positive { + { "Double", -1.0 } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary positive2 { + { "Double", 3.0 } + }; + positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Double", 1.0 } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Double", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, NotListString) { + using namespace openspace::documentation; + using namespace std::string_literals; + + Documentation doc { + { "String" , new StringNotInListVerifier({ "0"s, "1"s, "2"s }) } + }; + + ghoul::Dictionary positive { + { "String", "string"s } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary positive2 { + { "String", "foo_string"s } + }; + positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "String", "1"s } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("String", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, AnnotationBool) { + using namespace openspace::documentation; + + Documentation doc { + { "Bool", new BoolAnnotationVerifier("Bool") } + }; + + ghoul::Dictionary positive { + { "Bool", true } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Bool", 0 } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Bool", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, AnnotationInt) { + using namespace openspace::documentation; + + Documentation doc { + { "Int", new IntAnnotationVerifier("Int") } + }; + + ghoul::Dictionary positive { + { "Int", 1 } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Int", 1.1 } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Int", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, AnnotationDouble) { + using namespace openspace::documentation; + + Documentation doc { + { "Double", new DoubleAnnotationVerifier("Double") } + }; + + ghoul::Dictionary positive { + { "Double", 0.0 } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Double", true } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Double", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, AnnotationString) { + using namespace openspace::documentation; + using namespace std::string_literals; + + Documentation doc { + { "String", new StringAnnotationVerifier("String") } + }; + + ghoul::Dictionary positive { + { "String", ""s } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "String", 1 } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("String", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, AnnotationTable) { + using namespace openspace::documentation; + + Documentation doc { + { "Table", new TableAnnotationVerifier("Table") } + }; + + ghoul::Dictionary positive { + { "Table", ghoul::Dictionary{} } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Table", 1 } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Table", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, InRangeInt) { + using namespace openspace::documentation; + + Documentation doc { + { "Int", new InRangeVerifier(0, 5) } + }; + + ghoul::Dictionary positive { + { "Int", 2 } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary positive2 { + { "Int", 0 } + }; + positiveRes = testSpecification(doc, positive2); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary positive3 { + { "Int", 5 } + }; + positiveRes = testSpecification(doc, positive3); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Int", 10 } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Int", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, InRangeDouble) { + using namespace openspace::documentation; + + Documentation doc { + { "Double", new InRangeVerifier(0.0, 5.0) } + }; + + ghoul::Dictionary positive { + { "Double", 2.0 } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary positive2 { + { "Double", 0.0 } + }; + positiveRes = testSpecification(doc, positive2); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary positive3 { + { "Double", 5.0 } + }; + positiveRes = testSpecification(doc, positive3); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary positive4 { + { "Double", 1.5 } + }; + positiveRes = testSpecification(doc, positive4); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Double", 10.0 } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Double", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, NotInRangeInt) { + using namespace openspace::documentation; + + Documentation doc { + { "Int", new NotInRangeVerifier(0, 5) } + }; + + ghoul::Dictionary positive { + { "Int", -1 } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary positive2 { + { "Int", 6 } + }; + positiveRes = testSpecification(doc, positive2); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Int", 2 } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Int", negativeRes.offenders[0]); + + ghoul::Dictionary negative2 { + { "Int", 0 } + }; + negativeRes = testSpecification(doc, negative2); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Int", negativeRes.offenders[0]); + + ghoul::Dictionary negative3 { + { "Int", 5 } + }; + negativeRes = testSpecification(doc, negative3); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Int", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, NotInRangeDouble) { + using namespace openspace::documentation; + + Documentation doc { + { "Double", new NotInRangeVerifier(0.0, 5.0) } + }; + + ghoul::Dictionary positive { + { "Double", -1.0 } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary positive2 { + { "Double", 6.0 } + }; + positiveRes = testSpecification(doc, positive2); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Double", 0.0 } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Double", negativeRes.offenders[0]); + + ghoul::Dictionary negative2 { + { "Double", 5.0 } + }; + negativeRes = testSpecification(doc, negative2); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Double", negativeRes.offenders[0]); + + ghoul::Dictionary negative3 { + { "Double", 2.5 } + }; + negativeRes = testSpecification(doc, negative3); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Double", negativeRes.offenders[0]); +} + + +//TEST_F(DocumentationTest, LessBool) { +// using namespace openspace::documentation; +// +// Documentation doc { +// }; +// +// ghoul::Dictionary positive { +// }; +// TestResult positiveRes = testSpecification(doc, positive); +// EXPECT_TRUE(positiveRes.success); +// EXPECT_EQ(0, positiveRes.offenders.size()); +// +// ghoul::Dictionary negative { +// }; +// TestResult negativeRes = testSpecification(doc, negative); +// EXPECT_FALSE(negativeRes.success); +// ASSERT_EQ(1, negativeRes.offenders.size()); +// EXPECT_EQ("", negativeRes.offenders[0]); +//} \ No newline at end of file From 45d034ad2a3a6a7bcdf0451d51182f1aaadf2509 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Tue, 13 Sep 2016 20:27:29 +0200 Subject: [PATCH 40/92] Enabling optional arguments Adding tests to the OpenSpaceTest --- ext/ghoul | 2 +- include/openspace/util/documentation.h | 5 +- src/util/documentation.cpp | 16 ++++-- tests/main.cpp | 2 + tests/test_documentation.inl | 77 ++++++++++++++++---------- 5 files changed, 67 insertions(+), 35 deletions(-) diff --git a/ext/ghoul b/ext/ghoul index 5120a2d60b..e10dc7cc5f 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 5120a2d60b61303369c305e66c4fcd334c249a02 +Subproject commit e10dc7cc5fbfd5c4d74b525f55ade7bc339e5bc6 diff --git a/include/openspace/util/documentation.h b/include/openspace/util/documentation.h index a049e785cc..d3470dfdc6 100644 --- a/include/openspace/util/documentation.h +++ b/include/openspace/util/documentation.h @@ -26,6 +26,7 @@ #define __DOCUMENTATION_H__ #include +#include #include #include @@ -43,6 +44,8 @@ struct TestResult { std::vector offenders; }; +using Optional = ghoul::Boolean; + struct Verifier { virtual TestResult operator()(const ghoul::Dictionary& dict, const std::string& key) const; @@ -54,7 +57,7 @@ struct Verifier { struct DocumentationEntry { - DocumentationEntry(std::string key, Verifier* t, bool optional = false, + DocumentationEntry(std::string key, Verifier* t, Optional optional = Optional::No, std::string doc = ""); std::string key; diff --git a/src/util/documentation.cpp b/src/util/documentation.cpp index c4fd5ca8a6..affa1d73ed 100644 --- a/src/util/documentation.cpp +++ b/src/util/documentation.cpp @@ -72,7 +72,8 @@ template struct AnnotationVerifier; TestResult Verifier::operator()(const ghoul::Dictionary& dict, - const std::string& key) const { + const std::string& key) const +{ bool testSuccess = test(dict, key); if (testSuccess) { return{ testSuccess, {} }; @@ -87,17 +88,22 @@ bool Verifier::test(const ghoul::Dictionary& dict, const std::string& key) const }; DocumentationEntry::DocumentationEntry(std::string key, Verifier* t, - bool optional, std::string doc) + Optional optional, std::string doc) : key(std::move(key)) , tester(std::move(t)) , optional(optional) , documentation(std::move(doc)) {} -TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& dictionary) { +TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& dictionary){ TestResult result; result.success = true; for (const auto& p : d) { + if (p.optional && !dictionary.hasKey(p.key)) { + // If the key is optional and it doesn't exist, we don't need to check it + // if the key exists, it has to be correct, however + continue; + } Verifier& verifier = *(p.tester); TestResult res = verifier(dictionary, p.key); if (!res.success) { @@ -177,7 +183,9 @@ TableVerifier::TableVerifier(Documentation d) : doc(std::move(d)) {} -TestResult TableVerifier::operator()(const ghoul::Dictionary& dict, const std::string& key) const { +TestResult TableVerifier::operator()(const ghoul::Dictionary& dict, + const std::string& key) const +{ if (dict.hasKeyAndValue(key)) { ghoul::Dictionary d = dict.value(key); TestResult res = testSpecification(doc, d); diff --git a/tests/main.cpp b/tests/main.cpp index 0cbe2b6040..354d923c9c 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -58,6 +58,8 @@ //#include #endif +#include + #include #include #include diff --git a/tests/test_documentation.inl b/tests/test_documentation.inl index ea48200ef1..4d002cbdba 100644 --- a/tests/test_documentation.inl +++ b/tests/test_documentation.inl @@ -30,14 +30,6 @@ #include -/* - * To test: - * optional values - * - * to add: - * external template instantiations -*/ - class DocumentationTest : public testing::Test {}; TEST_F(DocumentationTest, Constructor) { @@ -506,6 +498,54 @@ TEST_F(DocumentationTest, NestedTables) { EXPECT_EQ("Outer_Table2.Inner_Table.Inner_Inner_Int", negativeRes.offenders[2]); } +TEST_F(DocumentationTest, Optional) { + using namespace openspace::documentation; + + Documentation doc { + { "Bool_Force", new BoolVerifier, Optional::No }, + { "Bool_Optional", new BoolVerifier, Optional::Yes } + }; + + ghoul::Dictionary positive { + { "Bool_Force", true }, + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary positive2 { + { "Bool_Force", true }, + { "Bool_Optional", true } + }; + positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Bool_Force", negativeRes.offenders[0]); + + ghoul::Dictionary negative2 { + { "Bool_Optional", true } + }; + negativeRes = testSpecification(doc, negative2); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Bool_Force", negativeRes.offenders[0]); + + ghoul::Dictionary negative3 { + { "Bool_Force", true }, + { "Bool_Optional", 1 } + }; + negativeRes = testSpecification(doc, negative3); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("Bool_Optional", negativeRes.offenders[0]); +} + TEST_F(DocumentationTest, LessInt) { using namespace openspace::documentation; @@ -1421,24 +1461,3 @@ TEST_F(DocumentationTest, NotInRangeDouble) { ASSERT_EQ(1, negativeRes.offenders.size()); EXPECT_EQ("Double", negativeRes.offenders[0]); } - - -//TEST_F(DocumentationTest, LessBool) { -// using namespace openspace::documentation; -// -// Documentation doc { -// }; -// -// ghoul::Dictionary positive { -// }; -// TestResult positiveRes = testSpecification(doc, positive); -// EXPECT_TRUE(positiveRes.success); -// EXPECT_EQ(0, positiveRes.offenders.size()); -// -// ghoul::Dictionary negative { -// }; -// TestResult negativeRes = testSpecification(doc, negative); -// EXPECT_FALSE(negativeRes.success); -// ASSERT_EQ(1, negativeRes.offenders.size()); -// EXPECT_EQ("", negativeRes.offenders[0]); -//} \ No newline at end of file From a4fa9c0788d284ca4bfc29338598dd6cf1b21386 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Wed, 14 Sep 2016 09:27:34 +0200 Subject: [PATCH 41/92] Add Range checks to unit tests --- include/openspace/util/documentation.h | 1 - tests/test_documentation.inl | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/include/openspace/util/documentation.h b/include/openspace/util/documentation.h index d3470dfdc6..8ad21d5d30 100644 --- a/include/openspace/util/documentation.h +++ b/include/openspace/util/documentation.h @@ -55,7 +55,6 @@ struct Verifier { virtual std::string documentation() const = 0; }; - struct DocumentationEntry { DocumentationEntry(std::string key, Verifier* t, Optional optional = Optional::No, std::string doc = ""); diff --git a/tests/test_documentation.inl b/tests/test_documentation.inl index 4d002cbdba..2ba54e6918 100644 --- a/tests/test_documentation.inl +++ b/tests/test_documentation.inl @@ -78,6 +78,13 @@ TEST_F(DocumentationTest, Constructor) { doc.emplace_back("NotInListInt", new IntNotInListVerifier({ 0, 1 })); doc.emplace_back("NotInListString", new StringNotInListVerifier({ "", "a" })); + // Range Verifiers + doc.emplace_back("InListDouble", new DoubleInRangeVerifier({ 0.0, 1.0 })); + doc.emplace_back("InListInt", new IntInRangeVerifier({ 0, 1 })); + + doc.emplace_back("NotInListDouble", new DoubleNotInRangeVerifier({ 0.0, 1.0 })); + doc.emplace_back("NotInListInt", new IntNotInRangeVerifier({ 0, 1 })); + // Misc Verifiers doc.emplace_back("AnnotationBool", new BoolAnnotationVerifier("Bool")); doc.emplace_back("AnnotationDouble", new DoubleAnnotationVerifier("Double")); @@ -131,6 +138,13 @@ TEST_F(DocumentationTest, InitializerConstructor) { {"NotInListInt", new IntNotInListVerifier({ 0, 1 })}, {"NotInListString", new StringNotInListVerifier({ "", "a" })}, + // Range Verifiers + {"InRangeDouble", new DoubleInRangeVerifier{{0.0, 1.0}}, + {"InRangeInt", new IntInRangeVerifier{{0, 1}}, + + {"InRangeDouble", new DoubleNotInRangeVerifier{{ 0.0, 1.0 }}, + {"InRangeInt", new IntNotInRangeVerifier{{ 0, 1 }}, + // Misc Verifiers {"AnnotationBool", new BoolAnnotationVerifier("Bool")}, {"AnnotationDouble", new DoubleAnnotationVerifier("Double")}, From b87e30d0d28c120e1f81587fb99f9af6dfc58faa Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Wed, 14 Sep 2016 11:12:55 +0200 Subject: [PATCH 42/92] Correctly set argument description for setPropertyValueRegex --- src/scene/scene.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp index 9cffc86a82..5413b08adc 100644 --- a/src/scene/scene.cpp +++ b/src/scene/scene.cpp @@ -455,6 +455,7 @@ scripting::LuaLibrary Scene::luaLibrary() { { "setPropertyValueRegex", &luascriptfunctions::property_setValueRegex, + "string, *", "Sets all properties that pass the regular expression in the first " "argument. The second argument can be any type, but it has to match the " "type of the properties that matched the regular expression. The regular " From 03e7d183437c5cf53e308c484fecb16f886ab3a6 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Wed, 14 Sep 2016 11:13:29 +0200 Subject: [PATCH 43/92] Start with the work on enabling the ScriptEngine to output an HTML output --- include/openspace/scripting/scriptengine.h | 2 +- src/scripting/scriptengine.cpp | 115 +++++++++++++-------- 2 files changed, 74 insertions(+), 43 deletions(-) diff --git a/include/openspace/scripting/scriptengine.h b/include/openspace/scripting/scriptengine.h index cb7797e181..cadfaf4e2d 100644 --- a/include/openspace/scripting/scriptengine.h +++ b/include/openspace/scripting/scriptengine.h @@ -69,7 +69,7 @@ public: bool runScript(const std::string& script); bool runScriptFile(const std::string& filename); - bool writeDocumentation(const std::string& filename, const std::string& type) const; + void writeDocumentation(const std::string& filename, const std::string& type) const; bool writeLog(const std::string& script); diff --git a/src/scripting/scriptengine.cpp b/src/scripting/scriptengine.cpp index a795067bf6..cd5b416082 100644 --- a/src/scripting/scriptengine.cpp +++ b/src/scripting/scriptengine.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -51,7 +52,6 @@ namespace { //const lua_CFunction _printFunctionReplacement = luascriptfunctions::printInfo; const int _setTableOffset = -3; // -1 (top) -1 (first argument) -1 (second argument) - } void ScriptEngine::initialize() { @@ -487,41 +487,36 @@ std::vector ScriptEngine::allLuaFunctions() const { return result; } -bool ScriptEngine::writeDocumentation(const std::string& filename, const std::string& type) const { - if (type == "text") { - // The additional space between the longest function name and the descriptions - LDEBUG("Writing Lua documentation of type '" << type << - "' to file '" << filename << "'"); - std::ofstream file(filename); - if (!file.good()) { - LERROR("Could not open file '" << filename << "' for writing documentation"); - return false; +void ScriptEngine::writeDocumentation(const std::string& filename, const std::string& type) const { + auto concatenate = [](std::string library, std::string function) { + std::string total = "openspace."; + if (!library.empty()) { + total += std::move(library) + "."; } + total += std::move(function); + return total; + }; - auto concatenate = [](std::string library, std::string function) { - std::string total = "openspace."; - if (!library.empty()) - total += std::move(library) + "."; - total += std::move(function); - return total; - }; - + LDEBUG("Writing Lua documentation of type '" << type << + "' to file '" << filename << "'"); + if (type == "text") { // Settings const unsigned int lineWidth = 80; static const std::string whitespace = " \t"; static const std::string padding = " "; - const bool commandListArguments = true; + + // The additional space between the longest function name and the descriptions + + std::ofstream file; + file.exceptions(~std::ofstream::goodbit); + file.open(filename); file << "Available commands:\n"; // Now write out the functions - for (const LuaLibrary& library : _registeredLibraries) { - for (const LuaLibrary::Function& function : library.functions) { - - std::string functionName = concatenate(library.name, function.name); - file << padding << functionName; - if (commandListArguments) - file << "(" << function.argumentText << ")"; - file << std::endl; + for (const LuaLibrary& l : _registeredLibraries) { + for (const LuaLibrary::Function& f : l.functions) { + std::string name = concatenate(l.name, f.name); + file << padding << name << "(" << f.argumentText << ")" << std::endl; } } file << std::endl; @@ -529,24 +524,32 @@ bool ScriptEngine::writeDocumentation(const std::string& filename, const std::st // Now write out the functions definitions for (const LuaLibrary& library : _registeredLibraries) { for (const LuaLibrary::Function& function : library.functions) { - - std::string functionName = concatenate(library.name, function.name); - file << functionName << "(" << function.argumentText << "):" << std::endl; + std::string name = concatenate(library.name, function.name); + file << name << "(" << function.argumentText << "):" << std::endl; std::string remainingHelptext = function.helpText; - - // @CLEANUP This needs to become a bit prettier ---abock while (!remainingHelptext.empty()) { - const auto length = remainingHelptext.length(); - const auto paddingLength = padding.length(); + const size_t length = remainingHelptext.length(); + const size_t paddingLength = padding.length(); + if ((length + paddingLength) > lineWidth) { - auto lastSpace = remainingHelptext.find_last_of(whitespace, lineWidth - 1 - paddingLength); - if (lastSpace == remainingHelptext.npos) + size_t lastSpace = remainingHelptext.find_last_of( + whitespace, + lineWidth - 1 - paddingLength + ); + if (lastSpace == remainingHelptext.npos) { lastSpace = lineWidth; - file << padding << remainingHelptext.substr(0, lastSpace) << std::endl; - auto firstNotSpace = remainingHelptext.find_first_not_of(whitespace, lastSpace); - if (firstNotSpace == remainingHelptext.npos) + } + + file << padding << remainingHelptext.substr(0, lastSpace) << '\n'; + + size_t firstNotSpace = remainingHelptext.find_first_not_of( + whitespace, + lastSpace + ); + if (firstNotSpace == remainingHelptext.npos) { firstNotSpace = lastSpace; + } remainingHelptext = remainingHelptext.substr(firstNotSpace); } else { @@ -557,11 +560,39 @@ bool ScriptEngine::writeDocumentation(const std::string& filename, const std::st file << std::endl; } } - return true; + } + else if (type == "html") { + std::ofstream file; + file.exceptions(~std::ofstream::goodbit); + file.open(filename); + + // Create JSON + std::stringstream json; + json << "["; + + for (const LuaLibrary& l : _registeredLibraries) { + json << "{"; + + json << "\"library\": \"" << l.name << "\","; + json << "\"functions\": ["; + + for (const LuaLibrary::Function& f : l.functions) { + json << "{"; + json << "\"name\": \"" << f.name << "\", "; + json << "\"arguments\": \"" << f.argumentText << "\", "; + json << "\"help\": \"" << f.helpText << "\""; + json << "},"; + } + json << "]},"; + } + json << "]"; + + + std::string jsonText = json.str(); + } else { - LERROR("Undefined type '" << type << "' for Lua documentation"); - return false; + throw ghoul::RuntimeError("Undefined type '" + type + "' for Lua documentation"); } } From d606f90db97179a789cb5ecd3cce6cf3f46c9a49 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Wed, 14 Sep 2016 13:33:47 +0200 Subject: [PATCH 44/92] Fix compilation error in unit test --- tests/test_documentation.inl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_documentation.inl b/tests/test_documentation.inl index 2ba54e6918..a46bcae869 100644 --- a/tests/test_documentation.inl +++ b/tests/test_documentation.inl @@ -139,11 +139,11 @@ TEST_F(DocumentationTest, InitializerConstructor) { {"NotInListString", new StringNotInListVerifier({ "", "a" })}, // Range Verifiers - {"InRangeDouble", new DoubleInRangeVerifier{{0.0, 1.0}}, - {"InRangeInt", new IntInRangeVerifier{{0, 1}}, + {"InRangeDouble", new DoubleInRangeVerifier(0.0, 1.0)}, + {"InRangeInt", new IntInRangeVerifier(0, 1)}, - {"InRangeDouble", new DoubleNotInRangeVerifier{{ 0.0, 1.0 }}, - {"InRangeInt", new IntNotInRangeVerifier{{ 0, 1 }}, + {"InRangeDouble", new DoubleNotInRangeVerifier(0.0, 1.0)}, + {"InRangeInt", new IntNotInRangeVerifier(0, 1)}, // Misc Verifiers {"AnnotationBool", new BoolAnnotationVerifier("Bool")}, From bb52c33b04e2692a295dc6456cb82d03fd5a6b9e Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Wed, 14 Sep 2016 13:34:45 +0200 Subject: [PATCH 45/92] Ability for LuaDocumentationFile, PropertyDocumentationFile, and KeyboardMapping to write HTML output Adding those html files to the gitignore --- .gitignore | 3 ++ src/interaction/interactionhandler.cpp | 22 +++++++++- src/scene/scene.cpp | 58 ++++++++++++++++++++++---- 3 files changed, 75 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 29d61f2358..b6ff87250c 100644 --- a/.gitignore +++ b/.gitignore @@ -117,3 +117,6 @@ data/scene/rosetta/rosetta/obj/Rosetta.obj data/scene/rosetta/rosetta/rosetta/ data/scene/rosetta/rosetta/textures/ data/spice/Rosetta/ +KeyboardMapping.html +LuaScripting.html +Properties.html diff --git a/src/interaction/interactionhandler.cpp b/src/interaction/interactionhandler.cpp index a496a6b636..219461ed84 100644 --- a/src/interaction/interactionhandler.cpp +++ b/src/interaction/interactionhandler.cpp @@ -951,13 +951,33 @@ void InteractionHandler::bindKey(Key key, KeyModifier modifier, std::string lua) void InteractionHandler::writeKeyboardDocumentation(const std::string& type, const std::string& file) { if (type == "text") { - std::ofstream f(absPath(file)); + std::ofstream f; + f.exceptions(~std::ofstream::goodbit); + f.open(file); for (const auto& p : _keyLua) { f << std::to_string(p.first) << ": " << p.second << std::endl; } } + else if (type == "html") { + std::ofstream f; + f.exceptions(~std::ofstream::goodbit); + f.open(absPath(file)); + + std::stringstream json; + json << "["; + for (const auto& p : _keyLua) { + json << "{"; + json << "\"key\": \"" << std::to_string(p.first) << "\","; + json << "\"script\": \"" << p.second << "\","; + json << "},"; + } + json << "]"; + + std::string jsonText = json.str(); + + } else { throw ghoul::RuntimeError( "Unsupported keyboard documentation type '" + type + "'", diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp index 5413b08adc..300f2d856b 100644 --- a/src/scene/scene.cpp +++ b/src/scene/scene.cpp @@ -414,13 +414,11 @@ SceneGraph& Scene::sceneGraph() { } void Scene::writePropertyDocumentation(const std::string& filename, const std::string& type) { + LDEBUG("Writing documentation for properties"); if (type == "text") { - LDEBUG("Writing documentation for properties"); - std::ofstream file(filename); - if (!file.good()) { - LERROR("Could not open file '" << filename << "' for writing property documentation"); - return; - } + std::ofstream file; + file.exceptions(~std::ofstream::goodbit); + file.open(filename); using properties::Property; for (SceneGraphNode* node : _graph.nodes()) { @@ -429,13 +427,59 @@ void Scene::writePropertyDocumentation(const std::string& filename, const std::s file << node->name() << std::endl; for (Property* p : properties) { - file << p->fullyQualifiedIdentifier() << ": " << p->guiName() << std::endl; + file << p->fullyQualifiedIdentifier() << ": " << + p->guiName() << std::endl; } file << std::endl; } } } + else if (type == "html") { + std::ofstream file; + file.exceptions(~std::ofstream::goodbit); + file.open(filename); + + // Create JSON + std::function createJson = + [&createJson](properties::PropertyOwner* owner) -> std::string + { + std::stringstream json; + json << "{"; + json << "\"name\": \"" << owner->name() << "\","; + + json << "\"properties\": ["; + for (properties::Property* p : owner->properties()) { + json << "{"; + json << "\"id\": \"" << p->identifier() << "\","; + json << "\"fullyQualifiedId\": \"" << p->fullyQualifiedIdentifier() << "\","; + json << "\"guiName\": \"" << p->guiName() << "\","; + json << "},"; + } + json << "],"; + + json << "\"propertyOwner\": ["; + for (properties::PropertyOwner* o : owner->propertySubOwners()) { + json << createJson(o); + } + json << "],"; + json << "},"; + + return json.str(); + }; + + + std::stringstream json; + json << "["; + for (SceneGraphNode* node : _graph.nodes()) { + json << createJson(node); + } + + json << "]"; + + std::string jsonText = json.str(); + + } else LERROR("Undefined type '" << type << "' for Property documentation"); } From dbc9b7ae4ef8c4656158565051211604f0bee287 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Wed, 14 Sep 2016 14:44:51 +0200 Subject: [PATCH 46/92] Move documentation to their own folder --- .../{util => documentation}/documentation.h | 0 .../{util => documentation}/documentation.inl | 0 .../documentation/documentationengine.h | 28 ++++++++++++++++ src/CMakeLists.txt | 8 +++-- src/{util => documentation}/documentation.cpp | 2 +- src/documentation/documentationengine.cpp | 33 +++++++++++++++++++ tests/test_documentation.inl | 2 +- 7 files changed, 68 insertions(+), 5 deletions(-) rename include/openspace/{util => documentation}/documentation.h (100%) rename include/openspace/{util => documentation}/documentation.inl (100%) create mode 100644 include/openspace/documentation/documentationengine.h rename src/{util => documentation}/documentation.cpp (99%) create mode 100644 src/documentation/documentationengine.cpp diff --git a/include/openspace/util/documentation.h b/include/openspace/documentation/documentation.h similarity index 100% rename from include/openspace/util/documentation.h rename to include/openspace/documentation/documentation.h diff --git a/include/openspace/util/documentation.inl b/include/openspace/documentation/documentation.inl similarity index 100% rename from include/openspace/util/documentation.inl rename to include/openspace/documentation/documentation.inl diff --git a/include/openspace/documentation/documentationengine.h b/include/openspace/documentation/documentationengine.h new file mode 100644 index 0000000000..4d4c091b39 --- /dev/null +++ b/include/openspace/documentation/documentationengine.h @@ -0,0 +1,28 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __DOCUMENTATIONENGINE_H__ +#define __DOCUMENTATIONENGINE_H__ + +#endif // __DOCUMENTATIONENGINE_H__ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c50e7a7561..244b299a35 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -24,6 +24,8 @@ set(OPENSPACE_SOURCE ${OPENSPACE_BASE_DIR}/src/openspace.cpp + ${OPENSPACE_BASE_DIR}/src/documentation/documentation.cpp + ${OPENSPACE_BASE_DIR}/src/documentation/documentationengine.cpp ${OPENSPACE_BASE_DIR}/src/engine/configurationmanager.cpp ${OPENSPACE_BASE_DIR}/src/engine/downloadmanager.cpp ${OPENSPACE_BASE_DIR}/src/engine/logfactory.cpp @@ -86,7 +88,6 @@ set(OPENSPACE_SOURCE ${OPENSPACE_BASE_DIR}/src/util/blockplaneintersectiongeometry.cpp ${OPENSPACE_BASE_DIR}/src/util/boxgeometry.cpp ${OPENSPACE_BASE_DIR}/src/util/camera.cpp - ${OPENSPACE_BASE_DIR}/src/util/documentation.cpp ${OPENSPACE_BASE_DIR}/src/util/factorymanager.cpp ${OPENSPACE_BASE_DIR}/src/util/keys.cpp ${OPENSPACE_BASE_DIR}/src/util/openspacemodule.cpp @@ -106,6 +107,9 @@ set(OPENSPACE_SOURCE set(OPENSPACE_HEADER ${OPENSPACE_BASE_DIR}/include/openspace/openspace.h + ${OPENSPACE_BASE_DIR}/include/openspace/documentation/documentation.h + ${OPENSPACE_BASE_DIR}/include/openspace/documentation/documentation.inl + ${OPENSPACE_BASE_DIR}/include/openspace/documentation/documentationengine.h ${OPENSPACE_BASE_DIR}/include/openspace/engine/configurationmanager.h ${OPENSPACE_BASE_DIR}/include/openspace/engine/downloadmanager.h ${OPENSPACE_BASE_DIR}/include/openspace/engine/logfactory.h @@ -173,8 +177,6 @@ set(OPENSPACE_HEADER ${OPENSPACE_BASE_DIR}/include/openspace/util/blockplaneintersectiongeometry.h ${OPENSPACE_BASE_DIR}/include/openspace/util/boxgeometry.h ${OPENSPACE_BASE_DIR}/include/openspace/util/camera.h - ${OPENSPACE_BASE_DIR}/include/openspace/util/documentation.h - ${OPENSPACE_BASE_DIR}/include/openspace/util/documentation.inl ${OPENSPACE_BASE_DIR}/include/openspace/util/factorymanager.h ${OPENSPACE_BASE_DIR}/include/openspace/util/factorymanager.inl ${OPENSPACE_BASE_DIR}/include/openspace/util/keys.h diff --git a/src/util/documentation.cpp b/src/documentation/documentation.cpp similarity index 99% rename from src/util/documentation.cpp rename to src/documentation/documentation.cpp index affa1d73ed..ae86af64f9 100644 --- a/src/util/documentation.cpp +++ b/src/documentation/documentation.cpp @@ -22,7 +22,7 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include +#include namespace std { std::string to_string(std::string value) { diff --git a/src/documentation/documentationengine.cpp b/src/documentation/documentationengine.cpp new file mode 100644 index 0000000000..efc4309bae --- /dev/null +++ b/src/documentation/documentationengine.cpp @@ -0,0 +1,33 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +namespace openspace { +namespace documentation { + + + +} // namespace documentation +} // namespace openspace diff --git a/tests/test_documentation.inl b/tests/test_documentation.inl index a46bcae869..ba9eff6b76 100644 --- a/tests/test_documentation.inl +++ b/tests/test_documentation.inl @@ -24,7 +24,7 @@ #include "gtest/gtest.h" -#include +#include #include From 26d2ca3d328bfb35804a93381d48306ffd92f436 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Wed, 14 Sep 2016 15:41:05 +0200 Subject: [PATCH 47/92] Support wildcards in documentation --- src/documentation/documentation.cpp | 57 ++++++++++---- tests/test_documentation.inl | 117 +++++++++++++++++++++++++++- 2 files changed, 159 insertions(+), 15 deletions(-) diff --git a/src/documentation/documentation.cpp b/src/documentation/documentation.cpp index ae86af64f9..83c9fc3c27 100644 --- a/src/documentation/documentation.cpp +++ b/src/documentation/documentation.cpp @@ -24,6 +24,12 @@ #include +#include + +namespace { + const std::string Wildcard = "*"; +} // namespace + namespace std { std::string to_string(std::string value) { return value; @@ -99,22 +105,47 @@ TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& di result.success = true; for (const auto& p : d) { - if (p.optional && !dictionary.hasKey(p.key)) { - // If the key is optional and it doesn't exist, we don't need to check it - // if the key exists, it has to be correct, however - continue; + if (p.key == Wildcard) { + for (const std::string& key : dictionary.keys()) { + Verifier& verifier = *(p.tester); + TestResult res = verifier(dictionary, key); + if (!res.success) { + result.success = false; + result.offenders.insert( + result.offenders.end(), + res.offenders.begin(), + res.offenders.end() + ); + } + } } - Verifier& verifier = *(p.tester); - TestResult res = verifier(dictionary, p.key); - if (!res.success) { - result.success = false; - result.offenders.insert( - result.offenders.end(), - res.offenders.begin(), - res.offenders.end() - ); + else { + if (p.optional && !dictionary.hasKey(p.key)) { + // If the key is optional and it doesn't exist, we don't need to check it + // if the key exists, it has to be correct, however + continue; + } + Verifier& verifier = *(p.tester); + TestResult res = verifier(dictionary, p.key); + if (!res.success) { + result.success = false; + result.offenders.insert( + result.offenders.end(), + res.offenders.begin(), + res.offenders.end() + ); + } } } + + // Make the offenders unique so that they only appear once in the list + std::set uniqueOffenders( + result.offenders.begin(), result.offenders.end() + ); + result.offenders = std::vector( + uniqueOffenders.begin(), uniqueOffenders.end() + ); + return result; } diff --git a/tests/test_documentation.inl b/tests/test_documentation.inl index ba9eff6b76..dfe11b297a 100644 --- a/tests/test_documentation.inl +++ b/tests/test_documentation.inl @@ -250,7 +250,7 @@ TEST_F(DocumentationTest, IntVerifier) { ASSERT_EQ(1, negativeRes.offenders.size()); EXPECT_EQ("Int", negativeRes.offenders[0]); - ghoul::Dictionary negativeExist{ + ghoul::Dictionary negativeExist { { "Int2", 0 } }; negativeRes = testSpecification(doc, negative); @@ -282,7 +282,7 @@ TEST_F(DocumentationTest, StringVerifier) { ASSERT_EQ(1, negativeRes.offenders.size()); EXPECT_EQ("String", negativeRes.offenders[0]); - ghoul::Dictionary negativeExist{ + ghoul::Dictionary negativeExist { { "String2", ""s } }; negativeRes = testSpecification(doc, negative); @@ -1475,3 +1475,116 @@ TEST_F(DocumentationTest, NotInRangeDouble) { ASSERT_EQ(1, negativeRes.offenders.size()); EXPECT_EQ("Double", negativeRes.offenders[0]); } + +TEST_F(DocumentationTest, Wildcard) { + using namespace openspace::documentation; + + Documentation doc { + { "*", new IntVerifier } + }; + + ghoul::Dictionary positive { + { "a", 1 }, + { "b", 2 }, + { "c", 3 } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "a", false }, + { "b", 2 }, + { "c", 3 } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("a", negativeRes.offenders[0]); + + ghoul::Dictionary negative2 { + { "a", false }, + { "b", false }, + { "c", 3 } + }; + negativeRes = testSpecification(doc, negative2); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(2, negativeRes.offenders.size()); + EXPECT_EQ("a", negativeRes.offenders[0]); + EXPECT_EQ("b", negativeRes.offenders[1]); + + ghoul::Dictionary negative3 { + { "a", false }, + { "b", false }, + { "c", false } + }; + negativeRes = testSpecification(doc, negative3); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(3, negativeRes.offenders.size()); + EXPECT_EQ("a", negativeRes.offenders[0]); + EXPECT_EQ("b", negativeRes.offenders[1]); + EXPECT_EQ("c", negativeRes.offenders[2]); +} + +TEST_F(DocumentationTest, WildcardMixed) { + using namespace openspace::documentation; + + Documentation doc { + { "*", new IntVerifier }, + { "b", new IntGreaterVerifier(5) } + }; + + ghoul::Dictionary positive { + { "a", 1 }, + { "b", 8 }, + { "c", 3 } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "a", false }, + { "b", 2 }, + { "c", 3 } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(2, negativeRes.offenders.size()); + EXPECT_EQ("a", negativeRes.offenders[0]); + EXPECT_EQ("b", negativeRes.offenders[1]); + + ghoul::Dictionary negative2 { + { "a", false }, + { "b", false }, + { "c", 3 } + }; + negativeRes = testSpecification(doc, negative2); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(2, negativeRes.offenders.size()); + EXPECT_EQ("a", negativeRes.offenders[0]); + EXPECT_EQ("b", negativeRes.offenders[1]); + + ghoul::Dictionary negative3 { + { "a", false }, + { "b", 1 }, + { "c", false } + }; + negativeRes = testSpecification(doc, negative3); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(3, negativeRes.offenders.size()); + EXPECT_EQ("a", negativeRes.offenders[0]); + EXPECT_EQ("b", negativeRes.offenders[1]); + EXPECT_EQ("c", negativeRes.offenders[2]); + + ghoul::Dictionary negative4 { + { "a", false }, + { "b", 10 }, + { "c", false } + }; + negativeRes = testSpecification(doc, negative4); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(2, negativeRes.offenders.size()); + EXPECT_EQ("a", negativeRes.offenders[0]); + EXPECT_EQ("c", negativeRes.offenders[1]); +} From 09c1b4be6d0edd76d9fa2d2e6703a4b3d85fe05b Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Wed, 14 Sep 2016 16:38:58 +0200 Subject: [PATCH 48/92] Add unit test to check nested optional/required combinations --- tests/test_documentation.inl | 64 ++++++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/tests/test_documentation.inl b/tests/test_documentation.inl index dfe11b297a..0ee05b4dfe 100644 --- a/tests/test_documentation.inl +++ b/tests/test_documentation.inl @@ -516,8 +516,8 @@ TEST_F(DocumentationTest, Optional) { using namespace openspace::documentation; Documentation doc { - { "Bool_Force", new BoolVerifier, Optional::No }, - { "Bool_Optional", new BoolVerifier, Optional::Yes } + { "Bool_Force", new BoolVerifier, "", Optional::No }, + { "Bool_Optional", new BoolVerifier, "", Optional::Yes } }; ghoul::Dictionary positive { @@ -560,6 +560,66 @@ TEST_F(DocumentationTest, Optional) { EXPECT_EQ("Bool_Optional", negativeRes.offenders[0]); } +TEST_F(DocumentationTest, RequiredInOptional) { + using namespace openspace::documentation; + + Documentation doc { + { + "a", + new TableVerifier({ + { + "b", + new IntVerifier + }, + { + "c", + new IntVerifier, + "", + Optional::Yes + } + }), + "", + Optional::Yes + } + }; + + ghoul::Dictionary positive { + { + "a", ghoul::Dictionary{ + { "b", 1 } + } + } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary positive2 { + { + "a", ghoul::Dictionary{ + { "b", 1 }, + { "c", 2 } + } + } + }; + positiveRes = testSpecification(doc, positive2); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary positive3 {}; + positiveRes = testSpecification(doc, positive3); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "a", ghoul::Dictionary{ { "c", 2 }}} + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("a.b", negativeRes.offenders[0]); +} + TEST_F(DocumentationTest, LessInt) { using namespace openspace::documentation; From 8bbf1c3d0dca6360d83fd00a759ea751aaee4ec2 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Wed, 14 Sep 2016 16:39:43 +0200 Subject: [PATCH 49/92] Change arrangement of optional and help text arguments --- include/openspace/documentation/documentation.h | 4 ++-- src/documentation/documentation.cpp | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/include/openspace/documentation/documentation.h b/include/openspace/documentation/documentation.h index 8ad21d5d30..f8d86556e1 100644 --- a/include/openspace/documentation/documentation.h +++ b/include/openspace/documentation/documentation.h @@ -56,8 +56,8 @@ struct Verifier { }; struct DocumentationEntry { - DocumentationEntry(std::string key, Verifier* t, Optional optional = Optional::No, - std::string doc = ""); + DocumentationEntry(std::string key, Verifier* t, std::string doc = "", + Optional optional = Optional::No); std::string key; std::shared_ptr tester; diff --git a/src/documentation/documentation.cpp b/src/documentation/documentation.cpp index 83c9fc3c27..25cba94fca 100644 --- a/src/documentation/documentation.cpp +++ b/src/documentation/documentation.cpp @@ -93,12 +93,13 @@ bool Verifier::test(const ghoul::Dictionary& dict, const std::string& key) const return false; }; -DocumentationEntry::DocumentationEntry(std::string key, Verifier* t, - Optional optional, std::string doc) +DocumentationEntry::DocumentationEntry(std::string key, Verifier* t, std::string doc, + Optional optional) : key(std::move(key)) , tester(std::move(t)) + , documentation(std::move(doc)) , optional(optional) - , documentation(std::move(doc)) {} +{} TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& dictionary){ TestResult result; From a0efbfb190cdb995722f6c6a17ead075468fcab6 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Wed, 14 Sep 2016 16:40:03 +0200 Subject: [PATCH 50/92] ScriptEngine uses HTML instead of html for consistency --- src/scripting/scriptengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripting/scriptengine.cpp b/src/scripting/scriptengine.cpp index cd5b416082..add0ba766d 100644 --- a/src/scripting/scriptengine.cpp +++ b/src/scripting/scriptengine.cpp @@ -561,7 +561,7 @@ void ScriptEngine::writeDocumentation(const std::string& filename, const std::st } } } - else if (type == "html") { + else if (type == "HTML") { std::ofstream file; file.exceptions(~std::ofstream::goodbit); file.open(filename); From 6df5f616bb65cc08c5baecf8a6f9eeff7932c24e Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Wed, 14 Sep 2016 16:44:00 +0200 Subject: [PATCH 51/92] Change LogFactory and ScriptEngine to use html instead of HTML for even more consistency --- src/engine/logfactory.cpp | 2 +- src/scripting/scriptengine.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/logfactory.cpp b/src/engine/logfactory.cpp index 2b5f2cd226..21a83f7c87 100644 --- a/src/engine/logfactory.cpp +++ b/src/engine/logfactory.cpp @@ -39,7 +39,7 @@ namespace { const std::string keyCategoryStamping = "CategoryStamping"; const std::string keyLogLevelStamping = "LogLevelStamping"; - const std::string valueHtmlLog = "HTML"; + const std::string valueHtmlLog = "html"; const std::string valueTextLog = "Text"; } diff --git a/src/scripting/scriptengine.cpp b/src/scripting/scriptengine.cpp index add0ba766d..cd5b416082 100644 --- a/src/scripting/scriptengine.cpp +++ b/src/scripting/scriptengine.cpp @@ -561,7 +561,7 @@ void ScriptEngine::writeDocumentation(const std::string& filename, const std::st } } } - else if (type == "HTML") { + else if (type == "html") { std::ofstream file; file.exceptions(~std::ofstream::goodbit); file.open(filename); From a02c5714c49b001063de48c4195cef2aa03964b0 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Wed, 14 Sep 2016 16:44:48 +0200 Subject: [PATCH 52/92] Use html instead of HTML for logging --- openspace.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openspace.cfg b/openspace.cfg index 61a05dd721..0e1f8a6d9a 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -36,7 +36,7 @@ return { LogLevel = "Debug", ImmediateFlush = true, Logs = { - { Type = "HTML", FileName = "${BASE_PATH}/log.html", Append = false } + { Type = "html", FileName = "${BASE_PATH}/log.html", Append = false } }, CapabilitiesVerbosity = "Full" }, From d84a0ee46a56a692fcee4964dc91e340de58395e Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Wed, 14 Sep 2016 17:35:06 +0200 Subject: [PATCH 53/92] Add and and or verifiers that combine multiple verifiers --- .../openspace/documentation/documentation.h | 24 +++++++ src/documentation/documentation.cpp | 25 +++++++ tests/test_documentation.inl | 65 +++++++++++++++++++ 3 files changed, 114 insertions(+) diff --git a/include/openspace/documentation/documentation.h b/include/openspace/documentation/documentation.h index f8d86556e1..de85ca0c0d 100644 --- a/include/openspace/documentation/documentation.h +++ b/include/openspace/documentation/documentation.h @@ -273,6 +273,30 @@ struct AnnotationVerifier : public T { std::string annotation; }; +// Boolean Verifiers + +struct AndVerifier : public Verifier { + AndVerifier(Verifier* a, Verifier* b); + + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + + std::string documentation() const override; + + std::shared_ptr a; + std::shared_ptr b; +}; + +struct OrVerifier : public Verifier { + OrVerifier(Verifier* a, Verifier* b); + + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + + std::string documentation() const override; + + std::shared_ptr a; + std::shared_ptr b; +}; + using IntLessVerifier = LessVerifier; using DoubleLessVerifier = LessVerifier; using IntLessEqualVerifier = LessEqualVerifier; diff --git a/src/documentation/documentation.cpp b/src/documentation/documentation.cpp index 25cba94fca..9cc663a924 100644 --- a/src/documentation/documentation.cpp +++ b/src/documentation/documentation.cpp @@ -235,5 +235,30 @@ std::string TableVerifier::documentation() const { return "Type: Table" + '\n' + generateDocumentation(doc); } +AndVerifier::AndVerifier(Verifier* a, Verifier* b) + : a(a) + , b(b) {} + +bool AndVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { + return a->test(dict, key) && b->test(dict, key); +} + +std::string AndVerifier::documentation() const { + return a->documentation() + " and " + b->documentation(); +} + +OrVerifier::OrVerifier(Verifier* a, Verifier* b) + : a(a) + , b(b) +{} + +bool OrVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { + return a->test(dict, key) || b->test(dict, key); +} + +std::string OrVerifier::documentation() const { + return a->documentation() + " or " + b->documentation(); +} + } // namespace documentation } // namespace openspace diff --git a/tests/test_documentation.inl b/tests/test_documentation.inl index 0ee05b4dfe..67e4ca87f9 100644 --- a/tests/test_documentation.inl +++ b/tests/test_documentation.inl @@ -1648,3 +1648,68 @@ TEST_F(DocumentationTest, WildcardMixed) { EXPECT_EQ("a", negativeRes.offenders[0]); EXPECT_EQ("c", negativeRes.offenders[1]); } + +TEST_F(DocumentationTest, AndOperator) { + using namespace openspace::documentation; + + Documentation doc { + { "a", new AndVerifier( + new IntGreaterEqualVerifier(2), new IntLessEqualVerifier(5) + ) + } + }; + + ghoul::Dictionary positive { + { "a", 4 } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "a", 0 } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("a", negativeRes.offenders[0]); + + ghoul::Dictionary negative2 { + { "a", 8 } + }; + negativeRes = testSpecification(doc, negative2); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("a", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, OrOperator) { + using namespace openspace::documentation; + using namespace std::string_literals; + + Documentation doc { + { "a", new OrVerifier(new StringVerifier, new IntVerifier)} + }; + + ghoul::Dictionary positive { + { "a", ""s} + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary positive2 { + { "a", 1 } + }; + positiveRes = testSpecification(doc, positive2); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "a", false } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("a", negativeRes.offenders[0]); +} From 3ddbb44524c39b04a2f1462f648517342b0ed27f Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Wed, 14 Sep 2016 17:49:17 +0200 Subject: [PATCH 54/92] Add documentation/specification for ConfigurationManager Add documentation testing to ConfigurationManager --- .../openspace/documentation/documentation.h | 9 +- include/openspace/documentation/documented.h | 45 +++ src/CMakeLists.txt | 2 + src/documentation/documentation.cpp | 4 + src/engine/configurationmanager.cpp | 15 +- src/engine/configurationmanager_doc.inl | 279 ++++++++++++++++++ 6 files changed, 352 insertions(+), 2 deletions(-) create mode 100644 include/openspace/documentation/documented.h create mode 100644 src/engine/configurationmanager_doc.inl diff --git a/include/openspace/documentation/documentation.h b/include/openspace/documentation/documentation.h index de85ca0c0d..87785a13c8 100644 --- a/include/openspace/documentation/documentation.h +++ b/include/openspace/documentation/documentation.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -39,12 +40,18 @@ namespace openspace { namespace documentation { +using Optional = ghoul::Boolean; + struct TestResult { bool success; std::vector offenders; }; -using Optional = ghoul::Boolean; +struct SpecificationError : public ghoul::RuntimeError { + SpecificationError(TestResult result, std::string component); + + TestResult result; +}; struct Verifier { virtual TestResult operator()(const ghoul::Dictionary& dict, diff --git a/include/openspace/documentation/documented.h b/include/openspace/documentation/documented.h new file mode 100644 index 0000000000..8082830bf1 --- /dev/null +++ b/include/openspace/documentation/documented.h @@ -0,0 +1,45 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __DOCUMENTED_H__ +#define __DOCUMENTED_H__ + +#include + +namespace openspace { +namespace documentation { + +template +struct Documented { + static Documentation Documentation() { + static_assert(false, "Missing template specialization for type" + typeid(T)); + } +}; + +} // namespace documentation +} // namespace openspace + + + +#endif // __DOCUMENTED_H__ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 244b299a35..ddcabb3938 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,6 +27,7 @@ set(OPENSPACE_SOURCE ${OPENSPACE_BASE_DIR}/src/documentation/documentation.cpp ${OPENSPACE_BASE_DIR}/src/documentation/documentationengine.cpp ${OPENSPACE_BASE_DIR}/src/engine/configurationmanager.cpp + ${OPENSPACE_BASE_DIR}/src/engine/configurationmanager_doc.inl ${OPENSPACE_BASE_DIR}/src/engine/downloadmanager.cpp ${OPENSPACE_BASE_DIR}/src/engine/logfactory.cpp ${OPENSPACE_BASE_DIR}/src/engine/moduleengine.cpp @@ -107,6 +108,7 @@ set(OPENSPACE_SOURCE set(OPENSPACE_HEADER ${OPENSPACE_BASE_DIR}/include/openspace/openspace.h + ${OPENSPACE_BASE_DIR}/include/openspace/documentation/documented.h ${OPENSPACE_BASE_DIR}/include/openspace/documentation/documentation.h ${OPENSPACE_BASE_DIR}/include/openspace/documentation/documentation.inl ${OPENSPACE_BASE_DIR}/include/openspace/documentation/documentationengine.h diff --git a/src/documentation/documentation.cpp b/src/documentation/documentation.cpp index 9cc663a924..1ab399c01d 100644 --- a/src/documentation/documentation.cpp +++ b/src/documentation/documentation.cpp @@ -76,6 +76,10 @@ template struct AnnotationVerifier; template struct AnnotationVerifier; template struct AnnotationVerifier; +SpecificationError::SpecificationError(TestResult result, std::string component) + : ghoul::RuntimeError("Error in specification", std::move(component)) + , result(std::move(result)) +{} TestResult Verifier::operator()(const ghoul::Dictionary& dict, const std::string& key) const diff --git a/src/engine/configurationmanager.cpp b/src/engine/configurationmanager.cpp index e72939c75d..dbc275ea28 100644 --- a/src/engine/configurationmanager.cpp +++ b/src/engine/configurationmanager.cpp @@ -32,6 +32,8 @@ using std::string; +#include "configurationmanager_doc.inl" + namespace { const string _configurationFile = "openspace.cfg"; const string _keyBasePath = "BASE_PATH"; @@ -94,8 +96,9 @@ string ConfigurationManager::findConfiguration(const string& filename) { void ConfigurationManager::loadFromFile(const string& filename) { using ghoul::filesystem::FileSystem; - if (!FileSys.fileExists(filename)) + if (!FileSys.fileExists(filename)) { throw ghoul::FileNotFoundError(filename, "ConfigurationManager"); + } // ${BASE_PATH} string basePathToken = FileSystem::TokenOpeningBraces + _keyBasePath @@ -109,6 +112,16 @@ void ConfigurationManager::loadFromFile(const string& filename) { // Loading the configuration file into ourselves ghoul::lua::loadDictionaryFromFile(filename, *this); + // Perform testing against the documentation/specification + using namespace openspace::documentation; + TestResult result = testSpecification( + Documented::Documentation(), + *this + ); + if (!result.success) { + throw SpecificationError(result, "ConfigurationManager"); + } + // Register all the paths ghoul::Dictionary dictionary = value(KeyPaths); diff --git a/src/engine/configurationmanager_doc.inl b/src/engine/configurationmanager_doc.inl new file mode 100644 index 0000000000..adee85ebac --- /dev/null +++ b/src/engine/configurationmanager_doc.inl @@ -0,0 +1,279 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +namespace openspace { +namespace documentation { + +template <> +struct Documented { + static Documentation Documentation() { + return { + { + "SGCTConfig", + new StringAnnotationVerifier("A valid SGCT configuration file"), + "The SGCT configuration file that determines the window and view frustum " + "settings that are being used when OpenSpace is started." + }, + { + "Scene", + new StringAnnotationVerifier( + "A valid scene file as described in the Scene documentation"), + "The scene description that is used to populate the application after " + "startup. The scene determines which objects are loaded, the startup " + "time and other scene-specific settings. More information is provided in " + "the Scene documentation." + }, + { + "Paths", + new TableVerifier({ + { "*", new StringVerifier } + }), + "A list of paths that are automatically registered with the file system. " + "If a key X is used in the table, it is then useable by referencing ${X} " + "in all other configuration files or scripts.", + Optional::Yes + }, + { + "Fonts", + new TableVerifier({ + { "*", new StringVerifier, "Font paths loadable by FreeType" } + }), + "A list of all fonts that will automatically be loaded on startup. Each " + "key-value pair contained in the table will become the name and the file " + "for a font.", + Optional::Yes + }, + { + "Logging", + new TableVerifier({ + { + "LogLevel", + new StringInListVerifier( + // List from logmanager.cpp::levelFromString + {"Debug", "Info", "Warning", "Error", "Fatal", "None" } + ), + "The severity of log messages that will be displayed. Only " + "messages of the selected level or higher will be displayed. All " + "levels below will be silently discarded. The order of " + "severities is: Debug < Info < Warning < Error < Fatal < None.", + Optional::Yes + }, + { + "ImmediateFlush", + new BoolVerifier, + "Determines whether error messages will be displayed immediately " + "or if it is acceptable to have a short delay, but being more " + "performant. If the delay is allowed ('true'), messages might " + "get lost if the application crashes shortly after a message was " + "logged.", + Optional::Yes + }, + { + "Logs", + new TableVerifier({ + { + "*", + new TableVerifier({ + { + "Type", + new StringInListVerifier({ + // List from logfactory.cpp::createLog + "text", "html" + }), + "The type of the new log to be generated." + }, + { + "FileName", + new StringVerifier, + "The filename to which the log will be written." + }, + { + "Append", + new BoolVerifier, + "Determines whether the file will be cleared at " + "startup or if the contents will be appended to " + "previous runs.", + Optional::Yes + } + }), + "Additional log files", + Optional::Yes + } + }), + "Per default, log messages are written to the console, the " + "onscreen text, and (if available) the Visual Studio output " + "window. This table can define other logging methods that will " + "be used additionally.", + Optional::Yes + }, + { + "CapabilitiesVerbosity", + new StringInListVerifier( + // List from OpenspaceEngine::initialize + { "None", "Minimal", "Default", "Full" } + ), + "At startup, a list of system capabilities is created and logged." + "This value determines how verbose this listing should be.", + Optional::Yes + } + }), + "Configurations for the logging of messages that are generated " + "throughout the code and are useful for debugging potential errors or " + "other information.", + Optional::Yes + }, + { + "LuaDocumentationFile", + new TableVerifier({ + { + "Type", + new StringInListVerifier( + // List from ScriptEngine::writeDocumentation + { "text", "html" } + ), + "The type of documentation that will be written." + }, + { + "File", + new StringVerifier, + "The filename that will be created on startup containing the " + "documentation of available Lua functions. Any existing file " + "will be silently overwritten." + } + }), + "Descriptions of whether and where to create a documentation file that " + "describes the available Lua functions that can be executed in scene " + "files or per console.", + Optional::Yes + }, + { + "PropertyDocumentationFile", + new TableVerifier({ + { + "Type", + new StringInListVerifier( + // List taken from Scene::writePropertyDocumentation + { "text", "html" } + ), + "The type of property documentation file that is created." + }, + { + "File", + new StringVerifier, + "The file that will be created on startup containing a list of " + "all properties in the scene. Any existing file will be silently " + "overwritten." + } + }), + "Descriptions of whether and where to create a list of all properties " + "that were created in the current scene.", + Optional::Yes + }, + { + "ScriptLogFile", + new TableVerifier({ + { + "Type", + new StringInListVerifier( + // List taken from ScriptEngine::writeLog + { "text" } + ), + "The type of logfile that will be created." + }, + { + "File", + new StringVerifier, + "The file that will be created on startup containing the log of " + "all Lua scripts that are executed. Any existing file (including " + "the results from previous runs) will be silently overwritten." + } + }), + "Contains a log of all Lua scripts that were executed in the last " + "session.", + Optional::Yes + }, + { + "KeyboardShortcuts", + new TableVerifier({ + { + "Type", + new StringInListVerifier( + // List from InteractionHandler::writeKeyboardDocumentation + { "text", "html" } + ), + "The type of keyboard binding documentation that should be " + "written." + }, + { + "File", + new StringVerifier, + "The file that will be created on startup containing the list of " + "all keyboard bindings with their respective Lua scripts." + } + }), + "Contains the collection of all keyboard shortcuts that were collected " + "during startup. For each key, it mentions which scripts will be " + "executed in the current session.", + Optional::Yes + }, + { + "ShutdownCountdown", + new DoubleGreaterEqualVerifier(0.0), + "The countdown that the application will wait between pressing ESC and " + "actually shutting down. If ESC is pressed again in this time, the " + "shutdown is aborted.", + Optional::Yes + }, + { + "DownloadRequestURL", + new OrVerifier( + new StringVerifier, + new TableVerifier({ + { "*", new StringVerifier } + }) + ), + "The URL from which files will be downloaded by the Launcher. This can " + "either be a single URL or a list of possible URLs from which the " + "Launcher can then choose.", + Optional::Yes + }, + { + "RenderingMethod", + new StringInListVerifier( + // List from RenderEngine::setRendererFromString + { "Framebuffer", "ABuffer" } + ), + "The renderer that is use after startup. The renderer 'ABuffer' requires " + "support for at least OpenGL 4.3", + Optional::Yes + } + }; + } +}; + + +} // namespace documentation +} // namespace openspace \ No newline at end of file From 6b146a6683ff3ad36b5771e67d24b407a143cd6c Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Wed, 14 Sep 2016 17:49:49 +0200 Subject: [PATCH 55/92] Add missing DocumentationEngine file --- .../documentation/documentationengine.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/include/openspace/documentation/documentationengine.h b/include/openspace/documentation/documentationengine.h index 4d4c091b39..82f2ef33b8 100644 --- a/include/openspace/documentation/documentationengine.h +++ b/include/openspace/documentation/documentationengine.h @@ -25,4 +25,21 @@ #ifndef __DOCUMENTATIONENGINE_H__ #define __DOCUMENTATIONENGINE_H__ +#include + +namespace openspace { +namespace documentation { + +class DocumentationEngine { +public: + + +private: +}; + +} // namespace documentation +} // namespace openspace + + + #endif // __DOCUMENTATIONENGINE_H__ From 0e4c70f467a0c5c8e14254b5aa782fc0a8f403dc Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Wed, 14 Sep 2016 17:50:35 +0200 Subject: [PATCH 56/92] Fix line endings --- src/engine/configurationmanager_doc.inl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engine/configurationmanager_doc.inl b/src/engine/configurationmanager_doc.inl index adee85ebac..53fc4c93f4 100644 --- a/src/engine/configurationmanager_doc.inl +++ b/src/engine/configurationmanager_doc.inl @@ -141,9 +141,9 @@ struct Documented { } }), "Configurations for the logging of messages that are generated " - "throughout the code and are useful for debugging potential errors or " - "other information.", - Optional::Yes + "throughout the code and are useful for debugging potential errors or " + "other information.", + Optional::Yes }, { "LuaDocumentationFile", From 752b82c3fbf6729965b535f7d95257a32bcc736f Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 15 Sep 2016 07:59:38 +0200 Subject: [PATCH 57/92] Rearrange Verifiers into their own files Make Documentation available for ConfigurationManager --- .../openspace/documentation/documentation.h | 319 +----------- include/openspace/documentation/documented.h | 45 -- include/openspace/documentation/verifier.h | 349 +++++++++++++ .../{documentation.inl => verifier.inl} | 0 .../openspace/engine/configurationmanager.h | 4 + src/CMakeLists.txt | 5 +- src/documentation/documentation.cpp | 148 +----- src/documentation/verifier.cpp | 181 +++++++ src/engine/configurationmanager.cpp | 2 +- src/engine/configurationmanager_doc.inl | 489 +++++++++--------- tests/test_documentation.inl | 1 + 11 files changed, 789 insertions(+), 754 deletions(-) delete mode 100644 include/openspace/documentation/documented.h create mode 100644 include/openspace/documentation/verifier.h rename include/openspace/documentation/{documentation.inl => verifier.inl} (100%) create mode 100644 src/documentation/verifier.cpp diff --git a/include/openspace/documentation/documentation.h b/include/openspace/documentation/documentation.h index 87785a13c8..5ec7b3555b 100644 --- a/include/openspace/documentation/documentation.h +++ b/include/openspace/documentation/documentation.h @@ -40,6 +40,8 @@ namespace openspace { namespace documentation { +struct Verifier; + using Optional = ghoul::Boolean; struct TestResult { @@ -53,15 +55,6 @@ struct SpecificationError : public ghoul::RuntimeError { TestResult result; }; -struct Verifier { - virtual TestResult operator()(const ghoul::Dictionary& dict, - const std::string& key) const; - - virtual bool test(const ghoul::Dictionary& dict, const std::string& key) const; - - virtual std::string documentation() const = 0; -}; - struct DocumentationEntry { DocumentationEntry(std::string key, Verifier* t, std::string doc = "", Optional optional = Optional::No); @@ -72,316 +65,16 @@ struct DocumentationEntry { std::string documentation; }; -using Documentation = std::vector; +using Documentation = std::vector; TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& dictionary); std::string generateDocumentation(const Documentation& d); -// General verifiers -template -struct TemplateVerifier : public Verifier { - using Type = T; -}; - -struct BoolVerifier : public TemplateVerifier { - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - - std::string documentation() const override; -}; - -struct DoubleVerifier : public TemplateVerifier { - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - - std::string documentation() const override; -}; - -struct IntVerifier : public TemplateVerifier { - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - - std::string documentation() const override; -}; - -struct StringVerifier : public TemplateVerifier { - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - - std::string documentation() const override; -}; - -struct TableVerifier : public TemplateVerifier { - TableVerifier(Documentation d = {}); - - TestResult operator()(const ghoul::Dictionary& dict, const std::string& key) const override; - - std::string documentation() const override; - - Documentation doc; -}; - -// Operator Verifiers - -template -struct LessVerifier : public T { - static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); - static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); - static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); - - LessVerifier(typename T::Type value); - - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - - std::string documentation() const; - - typename T::Type value; -}; - -template -struct LessEqualVerifier : public T { - static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); - static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); - static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); - - LessEqualVerifier(typename T::Type value); - - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - - std::string documentation() const override; - - typename T::Type value; -}; - -template -struct GreaterVerifier : public T { - static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); - static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); - static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); - - GreaterVerifier(typename T::Type value); - - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - - std::string documentation() const override; - - typename T::Type value; -}; - -template -struct GreaterEqualVerifier : public T { - static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); - static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); - static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); - - GreaterEqualVerifier(typename T::Type value); - - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - - std::string documentation() const override; - - typename T::Type value; -}; - -template -struct EqualVerifier : public T { - static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); - - EqualVerifier(typename T::Type value); - - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - - std::string documentation() const override; - - typename T::Type value; -}; - -template -struct UnequalVerifier : public T { - static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); - - UnequalVerifier(typename T::Type value); - - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - - std::string documentation() const override; - - typename T::Type value; -}; - -// List Verifiers - -template -struct InListVerifier : public T { - static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); - - InListVerifier(std::vector values); - - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - - std::string documentation() const override; - - std::vector values; -}; - -template -struct NotInListVerifier : public T { - static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); - - NotInListVerifier(std::vector values); - - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - - std::string documentation() const override; - - std::vector values; -}; - -// Range Verifiers -template -struct InRangeVerifier : public T { - static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); - static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); - static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); - - InRangeVerifier(typename T::Type lower, typename T::Type upper); - - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - - std::string documentation() const override; - - typename T::Type lower; - typename T::Type upper; -}; - -template -struct NotInRangeVerifier : public T { - static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); - static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); - static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); - - NotInRangeVerifier(typename T::Type lower, typename T::Type upper); - - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - - std::string documentation() const override; - - typename T::Type lower; - typename T::Type upper; -}; - -// Misc Verifiers - -template -struct AnnotationVerifier : public T { - AnnotationVerifier(std::string annotation); - - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - - std::string documentation() const override; - - std::string annotation; -}; - -// Boolean Verifiers - -struct AndVerifier : public Verifier { - AndVerifier(Verifier* a, Verifier* b); - - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - - std::string documentation() const override; - - std::shared_ptr a; - std::shared_ptr b; -}; - -struct OrVerifier : public Verifier { - OrVerifier(Verifier* a, Verifier* b); - - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - - std::string documentation() const override; - - std::shared_ptr a; - std::shared_ptr b; -}; - -using IntLessVerifier = LessVerifier; -using DoubleLessVerifier = LessVerifier; -using IntLessEqualVerifier = LessEqualVerifier; -using DoubleLessEqualVerifier = LessEqualVerifier; -using IntGreaterVerifier = GreaterVerifier; -using DoubleGreaterVerifier = GreaterVerifier; -using IntGreaterEqualVerifier = GreaterEqualVerifier; -using DoubleGreaterEqualVerifier = GreaterEqualVerifier; -using BoolEqualVerifier = EqualVerifier; -using IntEqualVerifier = EqualVerifier; -using DoubleEqualVerifier = EqualVerifier; -using StringEqualVerifier = EqualVerifier; -using BoolUnequalVerifier = UnequalVerifier; -using IntUnequalVerifier = UnequalVerifier; -using DoubleUnequalVerifier = UnequalVerifier; -using StringUnequalVerifier = UnequalVerifier; - -using BoolInListVerifier = InListVerifier; -using IntInListVerifier = InListVerifier; -using DoubleInListVerifier = InListVerifier; -using StringInListVerifier = InListVerifier; -using BoolNotInListVerifier = NotInListVerifier; -using IntNotInListVerifier = NotInListVerifier; -using DoubleNotInListVerifier = NotInListVerifier; -using StringNotInListVerifier = NotInListVerifier; - -using IntInRangeVerifier = InRangeVerifier; -using DoubleInRangeVerifier = InRangeVerifier; -using IntNotInRangeVerifier = NotInRangeVerifier; -using DoubleNotInRangeVerifier = NotInRangeVerifier; - -using BoolAnnotationVerifier = AnnotationVerifier; -using IntAnnotationVerifier = AnnotationVerifier; -using DoubleAnnotationVerifier = AnnotationVerifier; -using StringAnnotationVerifier = AnnotationVerifier; -using TableAnnotationVerifier = AnnotationVerifier; - - -extern template struct LessVerifier; -extern template struct LessVerifier; -extern template struct LessEqualVerifier; -extern template struct LessEqualVerifier; -extern template struct GreaterVerifier; -extern template struct GreaterVerifier; -extern template struct GreaterEqualVerifier; -extern template struct GreaterEqualVerifier; -extern template struct EqualVerifier; -extern template struct EqualVerifier; -extern template struct EqualVerifier; -extern template struct EqualVerifier; -extern template struct UnequalVerifier; -extern template struct UnequalVerifier; -extern template struct UnequalVerifier; -extern template struct UnequalVerifier; - -extern template struct InListVerifier; -extern template struct InListVerifier; -extern template struct InListVerifier; -extern template struct InListVerifier; -extern template struct NotInListVerifier; -extern template struct NotInListVerifier; -extern template struct NotInListVerifier; -extern template struct NotInListVerifier; - -extern template struct InRangeVerifier; -extern template struct InRangeVerifier; -extern template struct NotInRangeVerifier; -extern template struct NotInRangeVerifier; - -extern template struct AnnotationVerifier; -extern template struct AnnotationVerifier; -extern template struct AnnotationVerifier; -extern template struct AnnotationVerifier; -extern template struct AnnotationVerifier; - } // namespace documentation + +using documentation::Documentation; + } // namespace openspace -#include "documentation.inl" - #endif // __DOCUMENTATION_H__ diff --git a/include/openspace/documentation/documented.h b/include/openspace/documentation/documented.h deleted file mode 100644 index 8082830bf1..0000000000 --- a/include/openspace/documentation/documented.h +++ /dev/null @@ -1,45 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2016 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __DOCUMENTED_H__ -#define __DOCUMENTED_H__ - -#include - -namespace openspace { -namespace documentation { - -template -struct Documented { - static Documentation Documentation() { - static_assert(false, "Missing template specialization for type" + typeid(T)); - } -}; - -} // namespace documentation -} // namespace openspace - - - -#endif // __DOCUMENTED_H__ diff --git a/include/openspace/documentation/verifier.h b/include/openspace/documentation/verifier.h new file mode 100644 index 0000000000..e0db961a81 --- /dev/null +++ b/include/openspace/documentation/verifier.h @@ -0,0 +1,349 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __VERIFIER_H__ +#define __VERIFIER_H__ + +#include + +namespace openspace { +namespace documentation { + +struct Verifier { + virtual TestResult operator()(const ghoul::Dictionary& dict, + const std::string& key) const; + + virtual bool test(const ghoul::Dictionary& dict, const std::string& key) const; + + virtual std::string documentation() const = 0; +}; + +// General verifiers +template +struct TemplateVerifier : public Verifier { + using Type = T; +}; + +struct BoolVerifier : public TemplateVerifier { + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + + std::string documentation() const override; +}; + +struct DoubleVerifier : public TemplateVerifier { + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + + std::string documentation() const override; +}; + +struct IntVerifier : public TemplateVerifier { + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + + std::string documentation() const override; +}; + +struct StringVerifier : public TemplateVerifier { + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + + std::string documentation() const override; +}; + +struct TableVerifier : public TemplateVerifier { + TableVerifier(Documentation d = {}); + + TestResult operator()(const ghoul::Dictionary& dict, const std::string& key) const override; + + std::string documentation() const override; + + Documentation doc; +}; + +// Operator Verifiers + +template +struct LessVerifier : public T { + static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); + static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); + static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + + LessVerifier(typename T::Type value); + + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + + std::string documentation() const; + + typename T::Type value; +}; + +template +struct LessEqualVerifier : public T { + static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); + static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); + static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + + LessEqualVerifier(typename T::Type value); + + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + + std::string documentation() const override; + + typename T::Type value; +}; + +template +struct GreaterVerifier : public T { + static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); + static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); + static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + + GreaterVerifier(typename T::Type value); + + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + + std::string documentation() const override; + + typename T::Type value; +}; + +template +struct GreaterEqualVerifier : public T { + static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); + static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); + static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + + GreaterEqualVerifier(typename T::Type value); + + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + + std::string documentation() const override; + + typename T::Type value; +}; + +template +struct EqualVerifier : public T { + static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + + EqualVerifier(typename T::Type value); + + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + + std::string documentation() const override; + + typename T::Type value; +}; + +template +struct UnequalVerifier : public T { + static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + + UnequalVerifier(typename T::Type value); + + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + + std::string documentation() const override; + + typename T::Type value; +}; + +// List Verifiers + +template +struct InListVerifier : public T { + static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + + InListVerifier(std::vector values); + + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + + std::string documentation() const override; + + std::vector values; +}; + +template +struct NotInListVerifier : public T { + static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + + NotInListVerifier(std::vector values); + + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + + std::string documentation() const override; + + std::vector values; +}; + +// Range Verifiers +template +struct InRangeVerifier : public T { + static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); + static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); + static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + + InRangeVerifier(typename T::Type lower, typename T::Type upper); + + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + + std::string documentation() const override; + + typename T::Type lower; + typename T::Type upper; +}; + +template +struct NotInRangeVerifier : public T { + static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); + static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); + static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + + NotInRangeVerifier(typename T::Type lower, typename T::Type upper); + + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + + std::string documentation() const override; + + typename T::Type lower; + typename T::Type upper; +}; + +// Misc Verifiers + +template +struct AnnotationVerifier : public T { + AnnotationVerifier(std::string annotation); + + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + + std::string documentation() const override; + + std::string annotation; +}; + +// Boolean Verifiers + +struct AndVerifier : public Verifier { + AndVerifier(Verifier* a, Verifier* b); + + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + + std::string documentation() const override; + + std::shared_ptr a; + std::shared_ptr b; +}; + +struct OrVerifier : public Verifier { + OrVerifier(Verifier* a, Verifier* b); + + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + + std::string documentation() const override; + + std::shared_ptr a; + std::shared_ptr b; +}; + +using IntLessVerifier = LessVerifier; +using DoubleLessVerifier = LessVerifier; +using IntLessEqualVerifier = LessEqualVerifier; +using DoubleLessEqualVerifier = LessEqualVerifier; +using IntGreaterVerifier = GreaterVerifier; +using DoubleGreaterVerifier = GreaterVerifier; +using IntGreaterEqualVerifier = GreaterEqualVerifier; +using DoubleGreaterEqualVerifier = GreaterEqualVerifier; +using BoolEqualVerifier = EqualVerifier; +using IntEqualVerifier = EqualVerifier; +using DoubleEqualVerifier = EqualVerifier; +using StringEqualVerifier = EqualVerifier; +using BoolUnequalVerifier = UnequalVerifier; +using IntUnequalVerifier = UnequalVerifier; +using DoubleUnequalVerifier = UnequalVerifier; +using StringUnequalVerifier = UnequalVerifier; + +using BoolInListVerifier = InListVerifier; +using IntInListVerifier = InListVerifier; +using DoubleInListVerifier = InListVerifier; +using StringInListVerifier = InListVerifier; +using BoolNotInListVerifier = NotInListVerifier; +using IntNotInListVerifier = NotInListVerifier; +using DoubleNotInListVerifier = NotInListVerifier; +using StringNotInListVerifier = NotInListVerifier; + +using IntInRangeVerifier = InRangeVerifier; +using DoubleInRangeVerifier = InRangeVerifier; +using IntNotInRangeVerifier = NotInRangeVerifier; +using DoubleNotInRangeVerifier = NotInRangeVerifier; + +using BoolAnnotationVerifier = AnnotationVerifier; +using IntAnnotationVerifier = AnnotationVerifier; +using DoubleAnnotationVerifier = AnnotationVerifier; +using StringAnnotationVerifier = AnnotationVerifier; +using TableAnnotationVerifier = AnnotationVerifier; + + +extern template struct LessVerifier; +extern template struct LessVerifier; +extern template struct LessEqualVerifier; +extern template struct LessEqualVerifier; +extern template struct GreaterVerifier; +extern template struct GreaterVerifier; +extern template struct GreaterEqualVerifier; +extern template struct GreaterEqualVerifier; +extern template struct EqualVerifier; +extern template struct EqualVerifier; +extern template struct EqualVerifier; +extern template struct EqualVerifier; +extern template struct UnequalVerifier; +extern template struct UnequalVerifier; +extern template struct UnequalVerifier; +extern template struct UnequalVerifier; + +extern template struct InListVerifier; +extern template struct InListVerifier; +extern template struct InListVerifier; +extern template struct InListVerifier; +extern template struct NotInListVerifier; +extern template struct NotInListVerifier; +extern template struct NotInListVerifier; +extern template struct NotInListVerifier; + +extern template struct InRangeVerifier; +extern template struct InRangeVerifier; +extern template struct NotInRangeVerifier; +extern template struct NotInRangeVerifier; + +extern template struct AnnotationVerifier; +extern template struct AnnotationVerifier; +extern template struct AnnotationVerifier; +extern template struct AnnotationVerifier; +extern template struct AnnotationVerifier; + + +} // namespace documentation +} // namespace openspace + +#include "verifier.inl" + +#endif // __VERIFIER_H__ diff --git a/include/openspace/documentation/documentation.inl b/include/openspace/documentation/verifier.inl similarity index 100% rename from include/openspace/documentation/documentation.inl rename to include/openspace/documentation/verifier.inl diff --git a/include/openspace/engine/configurationmanager.h b/include/openspace/engine/configurationmanager.h index 23a5109043..bb105eab2b 100644 --- a/include/openspace/engine/configurationmanager.h +++ b/include/openspace/engine/configurationmanager.h @@ -25,6 +25,8 @@ #ifndef __CONFIGURATIONMANAGER_H__ #define __CONFIGURATIONMANAGER_H__ +#include + #include namespace openspace { @@ -123,6 +125,8 @@ public: */ void loadFromFile(const std::string& filename); + static Documentation Documentation(); + private: /** * Checks whether the loaded configuration file is complete, that is specifying the diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ddcabb3938..0f2b331c39 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -26,6 +26,7 @@ set(OPENSPACE_SOURCE ${OPENSPACE_BASE_DIR}/src/openspace.cpp ${OPENSPACE_BASE_DIR}/src/documentation/documentation.cpp ${OPENSPACE_BASE_DIR}/src/documentation/documentationengine.cpp + ${OPENSPACE_BASE_DIR}/src/documentation/verifier.cpp ${OPENSPACE_BASE_DIR}/src/engine/configurationmanager.cpp ${OPENSPACE_BASE_DIR}/src/engine/configurationmanager_doc.inl ${OPENSPACE_BASE_DIR}/src/engine/downloadmanager.cpp @@ -108,10 +109,10 @@ set(OPENSPACE_SOURCE set(OPENSPACE_HEADER ${OPENSPACE_BASE_DIR}/include/openspace/openspace.h - ${OPENSPACE_BASE_DIR}/include/openspace/documentation/documented.h ${OPENSPACE_BASE_DIR}/include/openspace/documentation/documentation.h - ${OPENSPACE_BASE_DIR}/include/openspace/documentation/documentation.inl ${OPENSPACE_BASE_DIR}/include/openspace/documentation/documentationengine.h + ${OPENSPACE_BASE_DIR}/include/openspace/documentation/verifier.h + ${OPENSPACE_BASE_DIR}/include/openspace/documentation/verifier.inl ${OPENSPACE_BASE_DIR}/include/openspace/engine/configurationmanager.h ${OPENSPACE_BASE_DIR}/include/openspace/engine/downloadmanager.h ${OPENSPACE_BASE_DIR}/include/openspace/engine/logfactory.h diff --git a/src/documentation/documentation.cpp b/src/documentation/documentation.cpp index 1ab399c01d..a34846f2eb 100644 --- a/src/documentation/documentation.cpp +++ b/src/documentation/documentation.cpp @@ -23,6 +23,7 @@ ****************************************************************************************/ #include +#include #include @@ -39,63 +40,11 @@ std::string to_string(std::string value) { namespace openspace { namespace documentation { -template struct LessVerifier; -template struct LessVerifier; -template struct LessEqualVerifier; -template struct LessEqualVerifier; -template struct GreaterVerifier; -template struct GreaterVerifier; -template struct GreaterEqualVerifier; -template struct GreaterEqualVerifier; -template struct EqualVerifier; -template struct EqualVerifier; -template struct EqualVerifier; -template struct EqualVerifier; -template struct UnequalVerifier; -template struct UnequalVerifier; -template struct UnequalVerifier; -template struct UnequalVerifier; - -template struct InListVerifier; -template struct InListVerifier; -template struct InListVerifier; -template struct InListVerifier; -template struct NotInListVerifier; -template struct NotInListVerifier; -template struct NotInListVerifier; -template struct NotInListVerifier; - -template struct InRangeVerifier; -template struct InRangeVerifier; -template struct NotInRangeVerifier; -template struct NotInRangeVerifier; - -template struct AnnotationVerifier; -template struct AnnotationVerifier; -template struct AnnotationVerifier; -template struct AnnotationVerifier; -template struct AnnotationVerifier; - SpecificationError::SpecificationError(TestResult result, std::string component) : ghoul::RuntimeError("Error in specification", std::move(component)) , result(std::move(result)) {} -TestResult Verifier::operator()(const ghoul::Dictionary& dict, - const std::string& key) const -{ - bool testSuccess = test(dict, key); - if (testSuccess) { - return{ testSuccess, {} }; - } - else { - return{ testSuccess, { key } }; - } -} - -bool Verifier::test(const ghoul::Dictionary& dict, const std::string& key) const { - return false; -}; DocumentationEntry::DocumentationEntry(std::string key, Verifier* t, std::string doc, Optional optional) @@ -169,100 +118,5 @@ std::string generateDocumentation(const Documentation& d) { return result; } -bool BoolVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { - return dict.hasKeyAndValue(key); -} - -std::string BoolVerifier::documentation() const { - return "Type: Boolean"; -} - -bool DoubleVerifier::test(const ghoul::Dictionary & dict, const std::string & key) const { - return dict.hasKeyAndValue(key); -} - -std::string DoubleVerifier::documentation() const { - return "Type: Double"; -} - -bool IntVerifier::test(const ghoul::Dictionary & dict, const std::string & key) const { - if (dict.hasKeyAndValue(key)) { - return true; - } - else { - if (dict.hasKeyAndValue(key)) { - // If we have a double value, we need to check if it is integer - double value = dict.value(key); - double intPart; - return modf(value, &intPart) == 0.0; - } - else { - // If we don't have a double value, we cannot have an int value - return false; - } - } -} - -std::string IntVerifier::documentation() const { - return "Type: Integer"; -} - -bool StringVerifier::test(const ghoul::Dictionary & dict, const std::string & key) const { - return dict.hasKeyAndValue(key); -} - -std::string StringVerifier::documentation() const { - return "Type: String"; -} - -TableVerifier::TableVerifier(Documentation d) - : doc(std::move(d)) -{} - -TestResult TableVerifier::operator()(const ghoul::Dictionary& dict, - const std::string& key) const -{ - if (dict.hasKeyAndValue(key)) { - ghoul::Dictionary d = dict.value(key); - TestResult res = testSpecification(doc, d); - - for (std::string& s : res.offenders) { - s = key + "." + s; - } - - return res; - } - return{ dict.hasKeyAndValue(key), { key } }; -} - -std::string TableVerifier::documentation() const { - return "Type: Table" + '\n' + generateDocumentation(doc); -} - -AndVerifier::AndVerifier(Verifier* a, Verifier* b) - : a(a) - , b(b) {} - -bool AndVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { - return a->test(dict, key) && b->test(dict, key); -} - -std::string AndVerifier::documentation() const { - return a->documentation() + " and " + b->documentation(); -} - -OrVerifier::OrVerifier(Verifier* a, Verifier* b) - : a(a) - , b(b) -{} - -bool OrVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { - return a->test(dict, key) || b->test(dict, key); -} - -std::string OrVerifier::documentation() const { - return a->documentation() + " or " + b->documentation(); -} - } // namespace documentation } // namespace openspace diff --git a/src/documentation/verifier.cpp b/src/documentation/verifier.cpp new file mode 100644 index 0000000000..163dd1dded --- /dev/null +++ b/src/documentation/verifier.cpp @@ -0,0 +1,181 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +namespace openspace { +namespace documentation { + +template struct LessVerifier; +template struct LessVerifier; +template struct LessEqualVerifier; +template struct LessEqualVerifier; +template struct GreaterVerifier; +template struct GreaterVerifier; +template struct GreaterEqualVerifier; +template struct GreaterEqualVerifier; +template struct EqualVerifier; +template struct EqualVerifier; +template struct EqualVerifier; +template struct EqualVerifier; +template struct UnequalVerifier; +template struct UnequalVerifier; +template struct UnequalVerifier; +template struct UnequalVerifier; + +template struct InListVerifier; +template struct InListVerifier; +template struct InListVerifier; +template struct InListVerifier; +template struct NotInListVerifier; +template struct NotInListVerifier; +template struct NotInListVerifier; +template struct NotInListVerifier; + +template struct InRangeVerifier; +template struct InRangeVerifier; +template struct NotInRangeVerifier; +template struct NotInRangeVerifier; + +template struct AnnotationVerifier; +template struct AnnotationVerifier; +template struct AnnotationVerifier; +template struct AnnotationVerifier; +template struct AnnotationVerifier; + +TestResult Verifier::operator()(const ghoul::Dictionary& dict, + const std::string& key) const +{ + bool testSuccess = test(dict, key); + if (testSuccess) { + return { testSuccess,{} }; + } + else { + return { testSuccess,{ key } }; + } +} + +bool Verifier::test(const ghoul::Dictionary& dict, const std::string& key) const { + return false; +}; + +bool BoolVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { + return dict.hasKeyAndValue(key); +} + +std::string BoolVerifier::documentation() const { + return "Type: Boolean"; +} + +bool DoubleVerifier::test(const ghoul::Dictionary & dict, const std::string & key) const { + return dict.hasKeyAndValue(key); +} + +std::string DoubleVerifier::documentation() const { + return "Type: Double"; +} + +bool IntVerifier::test(const ghoul::Dictionary & dict, const std::string & key) const { + if (dict.hasKeyAndValue(key)) { + return true; + } + else { + if (dict.hasKeyAndValue(key)) { + // If we have a double value, we need to check if it is integer + double value = dict.value(key); + double intPart; + return modf(value, &intPart) == 0.0; + } + else { + // If we don't have a double value, we cannot have an int value + return false; + } + } +} + +std::string IntVerifier::documentation() const { + return "Type: Integer"; +} + +bool StringVerifier::test(const ghoul::Dictionary & dict, const std::string & key) const { + return dict.hasKeyAndValue(key); +} + +std::string StringVerifier::documentation() const { + return "Type: String"; +} + +TableVerifier::TableVerifier(Documentation d) + : doc(std::move(d)) +{} + +TestResult TableVerifier::operator()(const ghoul::Dictionary& dict, + const std::string& key) const +{ + if (dict.hasKeyAndValue(key)) { + ghoul::Dictionary d = dict.value(key); + TestResult res = testSpecification(doc, d); + + for (std::string& s : res.offenders) { + s = key + "." + s; + } + + return res; + } + return { dict.hasKeyAndValue(key), { key } }; +} + +std::string TableVerifier::documentation() const { + return "Type: Table" + '\n' + generateDocumentation(doc); +} + +AndVerifier::AndVerifier(Verifier* a, Verifier* b) + : a(a) + , b(b) +{} + +bool AndVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { + return a->test(dict, key) && b->test(dict, key); +} + +std::string AndVerifier::documentation() const { + return a->documentation() + " and " + b->documentation(); +} + +OrVerifier::OrVerifier(Verifier* a, Verifier* b) + : a(a) + , b(b) +{} + +bool OrVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { + return a->test(dict, key) || b->test(dict, key); +} + +std::string OrVerifier::documentation() const { + return a->documentation() + " or " + b->documentation(); +} + + +} // namespace documentation +} // namespace openspace diff --git a/src/engine/configurationmanager.cpp b/src/engine/configurationmanager.cpp index dbc275ea28..f903f36f25 100644 --- a/src/engine/configurationmanager.cpp +++ b/src/engine/configurationmanager.cpp @@ -115,7 +115,7 @@ void ConfigurationManager::loadFromFile(const string& filename) { // Perform testing against the documentation/specification using namespace openspace::documentation; TestResult result = testSpecification( - Documented::Documentation(), + ConfigurationManager::Documentation(), *this ); if (!result.success) { diff --git a/src/engine/configurationmanager_doc.inl b/src/engine/configurationmanager_doc.inl index 53fc4c93f4..52474adb5a 100644 --- a/src/engine/configurationmanager_doc.inl +++ b/src/engine/configurationmanager_doc.inl @@ -22,258 +22,255 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include +#include namespace openspace { -namespace documentation { -template <> -struct Documented { - static Documentation Documentation() { - return { - { - "SGCTConfig", - new StringAnnotationVerifier("A valid SGCT configuration file"), - "The SGCT configuration file that determines the window and view frustum " - "settings that are being used when OpenSpace is started." - }, - { - "Scene", - new StringAnnotationVerifier( - "A valid scene file as described in the Scene documentation"), - "The scene description that is used to populate the application after " - "startup. The scene determines which objects are loaded, the startup " - "time and other scene-specific settings. More information is provided in " - "the Scene documentation." - }, - { - "Paths", +documentation::Documentation ConfigurationManager::Documentation() { + using namespace documentation; + + return { + { + "SGCTConfig", + new StringAnnotationVerifier("A valid SGCT configuration file"), + "The SGCT configuration file that determines the window and view frustum " + "settings that are being used when OpenSpace is started." + }, + { + "Scene", + new StringAnnotationVerifier( + "A valid scene file as described in the Scene documentation"), + "The scene description that is used to populate the application after " + "startup. The scene determines which objects are loaded, the startup " + "time and other scene-specific settings. More information is provided in " + "the Scene documentation." + }, + { + "Paths", + new TableVerifier({ + { "*", new StringVerifier } + }), + "A list of paths that are automatically registered with the file system. " + "If a key X is used in the table, it is then useable by referencing ${X} " + "in all other configuration files or scripts.", + Optional::Yes + }, + { + "Fonts", + new TableVerifier({ + { "*", new StringVerifier, "Font paths loadable by FreeType" } + }), + "A list of all fonts that will automatically be loaded on startup. Each " + "key-value pair contained in the table will become the name and the file " + "for a font.", + Optional::Yes + }, + { + "Logging", + new TableVerifier({ + { + "LogLevel", + new StringInListVerifier( + // List from logmanager.cpp::levelFromString + {"Debug", "Info", "Warning", "Error", "Fatal", "None" } + ), + "The severity of log messages that will be displayed. Only " + "messages of the selected level or higher will be displayed. All " + "levels below will be silently discarded. The order of " + "severities is: Debug < Info < Warning < Error < Fatal < None.", + Optional::Yes + }, + { + "ImmediateFlush", + new BoolVerifier, + "Determines whether error messages will be displayed immediately " + "or if it is acceptable to have a short delay, but being more " + "performant. If the delay is allowed ('true'), messages might " + "get lost if the application crashes shortly after a message was " + "logged.", + Optional::Yes + }, + { + "Logs", + new TableVerifier({ + { + "*", + new TableVerifier({ + { + "Type", + new StringInListVerifier({ + // List from logfactory.cpp::createLog + "text", "html" + }), + "The type of the new log to be generated." + }, + { + "FileName", + new StringVerifier, + "The filename to which the log will be written." + }, + { + "Append", + new BoolVerifier, + "Determines whether the file will be cleared at " + "startup or if the contents will be appended to " + "previous runs.", + Optional::Yes + } + }), + "Additional log files", + Optional::Yes + } + }), + "Per default, log messages are written to the console, the " + "onscreen text, and (if available) the Visual Studio output " + "window. This table can define other logging methods that will " + "be used additionally.", + Optional::Yes + }, + { + "CapabilitiesVerbosity", + new StringInListVerifier( + // List from OpenspaceEngine::initialize + { "None", "Minimal", "Default", "Full" } + ), + "At startup, a list of system capabilities is created and logged." + "This value determines how verbose this listing should be.", + Optional::Yes + } + }), + "Configurations for the logging of messages that are generated " + "throughout the code and are useful for debugging potential errors or " + "other information.", + Optional::Yes + }, + { + "LuaDocumentationFile", + new TableVerifier({ + { + "Type", + new StringInListVerifier( + // List from ScriptEngine::writeDocumentation + { "text", "html" } + ), + "The type of documentation that will be written." + }, + { + "File", + new StringVerifier, + "The filename that will be created on startup containing the " + "documentation of available Lua functions. Any existing file " + "will be silently overwritten." + } + }), + "Descriptions of whether and where to create a documentation file that " + "describes the available Lua functions that can be executed in scene " + "files or per console.", + Optional::Yes + }, + { + "PropertyDocumentationFile", + new TableVerifier({ + { + "Type", + new StringInListVerifier( + // List taken from Scene::writePropertyDocumentation + { "text", "html" } + ), + "The type of property documentation file that is created." + }, + { + "File", + new StringVerifier, + "The file that will be created on startup containing a list of " + "all properties in the scene. Any existing file will be silently " + "overwritten." + } + }), + "Descriptions of whether and where to create a list of all properties " + "that were created in the current scene.", + Optional::Yes + }, + { + "ScriptLogFile", + new TableVerifier({ + { + "Type", + new StringInListVerifier( + // List taken from ScriptEngine::writeLog + { "text" } + ), + "The type of logfile that will be created." + }, + { + "File", + new StringVerifier, + "The file that will be created on startup containing the log of " + "all Lua scripts that are executed. Any existing file (including " + "the results from previous runs) will be silently overwritten." + } + }), + "Contains a log of all Lua scripts that were executed in the last " + "session.", + Optional::Yes + }, + { + "KeyboardShortcuts", + new TableVerifier({ + { + "Type", + new StringInListVerifier( + // List from InteractionHandler::writeKeyboardDocumentation + { "text", "html" } + ), + "The type of keyboard binding documentation that should be " + "written." + }, + { + "File", + new StringVerifier, + "The file that will be created on startup containing the list of " + "all keyboard bindings with their respective Lua scripts." + } + }), + "Contains the collection of all keyboard shortcuts that were collected " + "during startup. For each key, it mentions which scripts will be " + "executed in the current session.", + Optional::Yes + }, + { + "ShutdownCountdown", + new DoubleGreaterEqualVerifier(0.0), + "The countdown that the application will wait between pressing ESC and " + "actually shutting down. If ESC is pressed again in this time, the " + "shutdown is aborted.", + Optional::Yes + }, + { + "DownloadRequestURL", + new OrVerifier( + new StringVerifier, new TableVerifier({ { "*", new StringVerifier } - }), - "A list of paths that are automatically registered with the file system. " - "If a key X is used in the table, it is then useable by referencing ${X} " - "in all other configuration files or scripts.", - Optional::Yes - }, - { - "Fonts", - new TableVerifier({ - { "*", new StringVerifier, "Font paths loadable by FreeType" } - }), - "A list of all fonts that will automatically be loaded on startup. Each " - "key-value pair contained in the table will become the name and the file " - "for a font.", - Optional::Yes - }, - { - "Logging", - new TableVerifier({ - { - "LogLevel", - new StringInListVerifier( - // List from logmanager.cpp::levelFromString - {"Debug", "Info", "Warning", "Error", "Fatal", "None" } - ), - "The severity of log messages that will be displayed. Only " - "messages of the selected level or higher will be displayed. All " - "levels below will be silently discarded. The order of " - "severities is: Debug < Info < Warning < Error < Fatal < None.", - Optional::Yes - }, - { - "ImmediateFlush", - new BoolVerifier, - "Determines whether error messages will be displayed immediately " - "or if it is acceptable to have a short delay, but being more " - "performant. If the delay is allowed ('true'), messages might " - "get lost if the application crashes shortly after a message was " - "logged.", - Optional::Yes - }, - { - "Logs", - new TableVerifier({ - { - "*", - new TableVerifier({ - { - "Type", - new StringInListVerifier({ - // List from logfactory.cpp::createLog - "text", "html" - }), - "The type of the new log to be generated." - }, - { - "FileName", - new StringVerifier, - "The filename to which the log will be written." - }, - { - "Append", - new BoolVerifier, - "Determines whether the file will be cleared at " - "startup or if the contents will be appended to " - "previous runs.", - Optional::Yes - } - }), - "Additional log files", - Optional::Yes - } - }), - "Per default, log messages are written to the console, the " - "onscreen text, and (if available) the Visual Studio output " - "window. This table can define other logging methods that will " - "be used additionally.", - Optional::Yes - }, - { - "CapabilitiesVerbosity", - new StringInListVerifier( - // List from OpenspaceEngine::initialize - { "None", "Minimal", "Default", "Full" } - ), - "At startup, a list of system capabilities is created and logged." - "This value determines how verbose this listing should be.", - Optional::Yes - } - }), - "Configurations for the logging of messages that are generated " - "throughout the code and are useful for debugging potential errors or " - "other information.", - Optional::Yes - }, - { - "LuaDocumentationFile", - new TableVerifier({ - { - "Type", - new StringInListVerifier( - // List from ScriptEngine::writeDocumentation - { "text", "html" } - ), - "The type of documentation that will be written." - }, - { - "File", - new StringVerifier, - "The filename that will be created on startup containing the " - "documentation of available Lua functions. Any existing file " - "will be silently overwritten." - } - }), - "Descriptions of whether and where to create a documentation file that " - "describes the available Lua functions that can be executed in scene " - "files or per console.", - Optional::Yes - }, - { - "PropertyDocumentationFile", - new TableVerifier({ - { - "Type", - new StringInListVerifier( - // List taken from Scene::writePropertyDocumentation - { "text", "html" } - ), - "The type of property documentation file that is created." - }, - { - "File", - new StringVerifier, - "The file that will be created on startup containing a list of " - "all properties in the scene. Any existing file will be silently " - "overwritten." - } - }), - "Descriptions of whether and where to create a list of all properties " - "that were created in the current scene.", - Optional::Yes - }, - { - "ScriptLogFile", - new TableVerifier({ - { - "Type", - new StringInListVerifier( - // List taken from ScriptEngine::writeLog - { "text" } - ), - "The type of logfile that will be created." - }, - { - "File", - new StringVerifier, - "The file that will be created on startup containing the log of " - "all Lua scripts that are executed. Any existing file (including " - "the results from previous runs) will be silently overwritten." - } - }), - "Contains a log of all Lua scripts that were executed in the last " - "session.", - Optional::Yes - }, - { - "KeyboardShortcuts", - new TableVerifier({ - { - "Type", - new StringInListVerifier( - // List from InteractionHandler::writeKeyboardDocumentation - { "text", "html" } - ), - "The type of keyboard binding documentation that should be " - "written." - }, - { - "File", - new StringVerifier, - "The file that will be created on startup containing the list of " - "all keyboard bindings with their respective Lua scripts." - } - }), - "Contains the collection of all keyboard shortcuts that were collected " - "during startup. For each key, it mentions which scripts will be " - "executed in the current session.", - Optional::Yes - }, - { - "ShutdownCountdown", - new DoubleGreaterEqualVerifier(0.0), - "The countdown that the application will wait between pressing ESC and " - "actually shutting down. If ESC is pressed again in this time, the " - "shutdown is aborted.", - Optional::Yes - }, - { - "DownloadRequestURL", - new OrVerifier( - new StringVerifier, - new TableVerifier({ - { "*", new StringVerifier } - }) - ), - "The URL from which files will be downloaded by the Launcher. This can " - "either be a single URL or a list of possible URLs from which the " - "Launcher can then choose.", - Optional::Yes - }, - { - "RenderingMethod", - new StringInListVerifier( - // List from RenderEngine::setRendererFromString - { "Framebuffer", "ABuffer" } - ), - "The renderer that is use after startup. The renderer 'ABuffer' requires " - "support for at least OpenGL 4.3", - Optional::Yes - } - }; - } + }) + ), + "The URL from which files will be downloaded by the Launcher. This can " + "either be a single URL or a list of possible URLs from which the " + "Launcher can then choose.", + Optional::Yes + }, + { + "RenderingMethod", + new StringInListVerifier( + // List from RenderEngine::setRendererFromString + { "Framebuffer", "ABuffer" } + ), + "The renderer that is use after startup. The renderer 'ABuffer' requires " + "support for at least OpenGL 4.3", + Optional::Yes + } + }; }; -} // namespace documentation } // namespace openspace \ No newline at end of file diff --git a/tests/test_documentation.inl b/tests/test_documentation.inl index 67e4ca87f9..fb36581302 100644 --- a/tests/test_documentation.inl +++ b/tests/test_documentation.inl @@ -25,6 +25,7 @@ #include "gtest/gtest.h" #include +#include #include From 00efcb7f5f2ec65d240c8f25605bf29a03804925 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 15 Sep 2016 09:19:21 +0200 Subject: [PATCH 58/92] Changing Documentation to enable a name associated with DocumentationEntries --- .../openspace/documentation/documentation.h | 15 +- include/openspace/documentation/verifier.h | 4 +- include/openspace/documentation/verifier.inl | 2 + src/documentation/documentation.cpp | 17 +- src/documentation/verifier.cpp | 2 +- src/engine/configurationmanager_doc.inl | 337 +++++++++-------- tests/test_documentation.inl | 357 ++++++++++-------- 7 files changed, 407 insertions(+), 327 deletions(-) diff --git a/include/openspace/documentation/documentation.h b/include/openspace/documentation/documentation.h index 5ec7b3555b..3f1074adcb 100644 --- a/include/openspace/documentation/documentation.h +++ b/include/openspace/documentation/documentation.h @@ -25,16 +25,12 @@ #ifndef __DOCUMENTATION_H__ #define __DOCUMENTATION_H__ -#include #include #include #include -#include -#include #include #include -#include #include namespace openspace { @@ -65,7 +61,16 @@ struct DocumentationEntry { std::string documentation; }; -using Documentation = std::vector; +using DocumentationEntries = std::vector; + +struct Documentation { + Documentation(std::string name = "", DocumentationEntries entries = {}); + Documentation(DocumentationEntries entries); + + std::string name; + DocumentationEntries entries; +}; + TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& dictionary); diff --git a/include/openspace/documentation/verifier.h b/include/openspace/documentation/verifier.h index e0db961a81..533c7e992a 100644 --- a/include/openspace/documentation/verifier.h +++ b/include/openspace/documentation/verifier.h @@ -70,13 +70,13 @@ struct StringVerifier : public TemplateVerifier { }; struct TableVerifier : public TemplateVerifier { - TableVerifier(Documentation d = {}); + TableVerifier(std::vector d = {}); TestResult operator()(const ghoul::Dictionary& dict, const std::string& key) const override; std::string documentation() const override; - Documentation doc; + std::vector doc; }; // Operator Verifiers diff --git a/include/openspace/documentation/verifier.inl b/include/openspace/documentation/verifier.inl index ad741cfe93..c2b8f0d02d 100644 --- a/include/openspace/documentation/verifier.inl +++ b/include/openspace/documentation/verifier.inl @@ -22,6 +22,8 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ +#include + namespace std { std::string to_string(std::string value); } diff --git a/src/documentation/documentation.cpp b/src/documentation/documentation.cpp index a34846f2eb..71b026b66e 100644 --- a/src/documentation/documentation.cpp +++ b/src/documentation/documentation.cpp @@ -54,11 +54,20 @@ DocumentationEntry::DocumentationEntry(std::string key, Verifier* t, std::string , optional(optional) {} +Documentation::Documentation(std::string name, DocumentationEntries entries) + : name(std::move(name)) + , entries(std::move(entries)) +{} + +Documentation::Documentation(DocumentationEntries entries) + : Documentation("", std::move(entries)) +{} + TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& dictionary){ TestResult result; result.success = true; - for (const auto& p : d) { + for (const auto& p : d.entries) { if (p.key == Wildcard) { for (const std::string& key : dictionary.keys()) { Verifier& verifier = *(p.tester); @@ -92,7 +101,8 @@ TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& di } } - // Make the offenders unique so that they only appear once in the list + // Remove duplicate offenders that might occur if multiple rules apply to a single + // key and more than one of these rules are broken std::set uniqueOffenders( result.offenders.begin(), result.offenders.end() ); @@ -107,7 +117,8 @@ std::string generateDocumentation(const Documentation& d) { using namespace std::string_literals; std::string result; - for (const auto& p : d) { + result += "Name: "s + d.name + '\n'; + for (const auto& p : d.entries) { result += p.key + '\n'; result += "Optional: "s + (p.optional ? "true" : "false") + '\n'; result += p.tester->documentation() + '\n'; diff --git a/src/documentation/verifier.cpp b/src/documentation/verifier.cpp index 163dd1dded..4c8a8a2543 100644 --- a/src/documentation/verifier.cpp +++ b/src/documentation/verifier.cpp @@ -126,7 +126,7 @@ std::string StringVerifier::documentation() const { return "Type: String"; } -TableVerifier::TableVerifier(Documentation d) +TableVerifier::TableVerifier(std::vector d) : doc(std::move(d)) {} diff --git a/src/engine/configurationmanager_doc.inl b/src/engine/configurationmanager_doc.inl index 52474adb5a..0203090f86 100644 --- a/src/engine/configurationmanager_doc.inl +++ b/src/engine/configurationmanager_doc.inl @@ -26,10 +26,12 @@ namespace openspace { -documentation::Documentation ConfigurationManager::Documentation() { +Documentation ConfigurationManager::Documentation() { using namespace documentation; return { + "ConfigurationManager", + { { "SGCTConfig", new StringAnnotationVerifier("A valid SGCT configuration file"), @@ -99,175 +101,176 @@ documentation::Documentation ConfigurationManager::Documentation() { { "Type", new StringInListVerifier({ - // List from logfactory.cpp::createLog - "text", "html" - }), - "The type of the new log to be generated." - }, - { - "FileName", - new StringVerifier, - "The filename to which the log will be written." - }, - { - "Append", - new BoolVerifier, - "Determines whether the file will be cleared at " - "startup or if the contents will be appended to " - "previous runs.", - Optional::Yes - } - }), - "Additional log files", - Optional::Yes - } - }), - "Per default, log messages are written to the console, the " - "onscreen text, and (if available) the Visual Studio output " - "window. This table can define other logging methods that will " - "be used additionally.", - Optional::Yes - }, - { - "CapabilitiesVerbosity", - new StringInListVerifier( - // List from OpenspaceEngine::initialize - { "None", "Minimal", "Default", "Full" } - ), - "At startup, a list of system capabilities is created and logged." - "This value determines how verbose this listing should be.", - Optional::Yes - } - }), - "Configurations for the logging of messages that are generated " - "throughout the code and are useful for debugging potential errors or " - "other information.", - Optional::Yes - }, + // List from logfactory.cpp::createLog + "text", "html" + }), + "The type of the new log to be generated." +}, +{ + "FileName", + new StringVerifier, + "The filename to which the log will be written." +}, +{ + "Append", + new BoolVerifier, + "Determines whether the file will be cleared at " + "startup or if the contents will be appended to " + "previous runs.", + Optional::Yes +} +}), +"Additional log files", +Optional::Yes +} +}), +"Per default, log messages are written to the console, the " + "onscreen text, and (if available) the Visual Studio output " + "window. This table can define other logging methods that will " + "be used additionally.", + Optional::Yes +}, +{ + "CapabilitiesVerbosity", + new StringInListVerifier( + // List from OpenspaceEngine::initialize + { "None", "Minimal", "Default", "Full" } + ), + "At startup, a list of system capabilities is created and logged." + "This value determines how verbose this listing should be.", + Optional::Yes +} +}), +"Configurations for the logging of messages that are generated " +"throughout the code and are useful for debugging potential errors or " +"other information.", +Optional::Yes +}, +{ + "LuaDocumentationFile", + new TableVerifier({ { - "LuaDocumentationFile", - new TableVerifier({ - { - "Type", - new StringInListVerifier( - // List from ScriptEngine::writeDocumentation - { "text", "html" } - ), - "The type of documentation that will be written." - }, - { - "File", - new StringVerifier, - "The filename that will be created on startup containing the " - "documentation of available Lua functions. Any existing file " - "will be silently overwritten." - } - }), - "Descriptions of whether and where to create a documentation file that " - "describes the available Lua functions that can be executed in scene " - "files or per console.", - Optional::Yes - }, - { - "PropertyDocumentationFile", - new TableVerifier({ - { - "Type", - new StringInListVerifier( - // List taken from Scene::writePropertyDocumentation - { "text", "html" } - ), - "The type of property documentation file that is created." - }, - { - "File", - new StringVerifier, - "The file that will be created on startup containing a list of " - "all properties in the scene. Any existing file will be silently " - "overwritten." - } - }), - "Descriptions of whether and where to create a list of all properties " - "that were created in the current scene.", - Optional::Yes - }, - { - "ScriptLogFile", - new TableVerifier({ - { - "Type", - new StringInListVerifier( - // List taken from ScriptEngine::writeLog - { "text" } - ), - "The type of logfile that will be created." - }, - { - "File", - new StringVerifier, - "The file that will be created on startup containing the log of " - "all Lua scripts that are executed. Any existing file (including " - "the results from previous runs) will be silently overwritten." - } - }), - "Contains a log of all Lua scripts that were executed in the last " - "session.", - Optional::Yes - }, - { - "KeyboardShortcuts", - new TableVerifier({ - { - "Type", - new StringInListVerifier( - // List from InteractionHandler::writeKeyboardDocumentation - { "text", "html" } - ), - "The type of keyboard binding documentation that should be " - "written." - }, - { - "File", - new StringVerifier, - "The file that will be created on startup containing the list of " - "all keyboard bindings with their respective Lua scripts." - } - }), - "Contains the collection of all keyboard shortcuts that were collected " - "during startup. For each key, it mentions which scripts will be " - "executed in the current session.", - Optional::Yes - }, - { - "ShutdownCountdown", - new DoubleGreaterEqualVerifier(0.0), - "The countdown that the application will wait between pressing ESC and " - "actually shutting down. If ESC is pressed again in this time, the " - "shutdown is aborted.", - Optional::Yes - }, - { - "DownloadRequestURL", - new OrVerifier( - new StringVerifier, - new TableVerifier({ - { "*", new StringVerifier } - }) - ), - "The URL from which files will be downloaded by the Launcher. This can " - "either be a single URL or a list of possible URLs from which the " - "Launcher can then choose.", - Optional::Yes - }, - { - "RenderingMethod", + "Type", new StringInListVerifier( - // List from RenderEngine::setRendererFromString - { "Framebuffer", "ABuffer" } + // List from ScriptEngine::writeDocumentation + { "text", "html" } ), - "The renderer that is use after startup. The renderer 'ABuffer' requires " - "support for at least OpenGL 4.3", - Optional::Yes + "The type of documentation that will be written." + }, + { + "File", + new StringVerifier, + "The filename that will be created on startup containing the " + "documentation of available Lua functions. Any existing file " + "will be silently overwritten." + } + }), + "Descriptions of whether and where to create a documentation file that " + "describes the available Lua functions that can be executed in scene " + "files or per console.", + Optional::Yes +}, +{ + "PropertyDocumentationFile", + new TableVerifier({ + { + "Type", + new StringInListVerifier( + // List taken from Scene::writePropertyDocumentation + { "text", "html" } + ), + "The type of property documentation file that is created." + }, + { + "File", + new StringVerifier, + "The file that will be created on startup containing a list of " + "all properties in the scene. Any existing file will be silently " + "overwritten." + } + }), + "Descriptions of whether and where to create a list of all properties " + "that were created in the current scene.", + Optional::Yes +}, +{ + "ScriptLogFile", + new TableVerifier({ + { + "Type", + new StringInListVerifier( + // List taken from ScriptEngine::writeLog + { "text" } + ), + "The type of logfile that will be created." + }, + { + "File", + new StringVerifier, + "The file that will be created on startup containing the log of " + "all Lua scripts that are executed. Any existing file (including " + "the results from previous runs) will be silently overwritten." + } + }), + "Contains a log of all Lua scripts that were executed in the last " + "session.", + Optional::Yes +}, +{ + "KeyboardShortcuts", + new TableVerifier({ + { + "Type", + new StringInListVerifier( + // List from InteractionHandler::writeKeyboardDocumentation + { "text", "html" } + ), + "The type of keyboard binding documentation that should be " + "written." + }, + { + "File", + new StringVerifier, + "The file that will be created on startup containing the list of " + "all keyboard bindings with their respective Lua scripts." + } + }), + "Contains the collection of all keyboard shortcuts that were collected " + "during startup. For each key, it mentions which scripts will be " + "executed in the current session.", + Optional::Yes +}, +{ + "ShutdownCountdown", + new DoubleGreaterEqualVerifier(0.0), + "The countdown that the application will wait between pressing ESC and " + "actually shutting down. If ESC is pressed again in this time, the " + "shutdown is aborted.", + Optional::Yes +}, +{ + "DownloadRequestURL", + new OrVerifier( + new StringVerifier, + new TableVerifier({ + { "*", new StringVerifier } + }) + ), + "The URL from which files will be downloaded by the Launcher. This can " + "either be a single URL or a list of possible URLs from which the " + "Launcher can then choose.", + Optional::Yes +}, +{ + "RenderingMethod", + new StringInListVerifier( + // List from RenderEngine::setRendererFromString + { "Framebuffer", "ABuffer" } + ), + "The renderer that is use after startup. The renderer 'ABuffer' requires " + "support for at least OpenGL 4.3", + Optional::Yes +} } }; }; diff --git a/tests/test_documentation.inl b/tests/test_documentation.inl index fb36581302..9ddc0efda4 100644 --- a/tests/test_documentation.inl +++ b/tests/test_documentation.inl @@ -39,127 +39,131 @@ TEST_F(DocumentationTest, Constructor) { Documentation doc; // Basic Verifiers - doc.emplace_back("BoolVerifier", new BoolVerifier); - doc.emplace_back("DoubleVerifier", new DoubleVerifier); - doc.emplace_back("IntVerifier", new IntVerifier); - doc.emplace_back("StringVerifier", new StringVerifier); - doc.emplace_back("TableVerifier", new TableVerifier); + doc.entries.emplace_back("BoolVerifier", new BoolVerifier); + doc.entries.emplace_back("DoubleVerifier", new DoubleVerifier); + doc.entries.emplace_back("IntVerifier", new IntVerifier); + doc.entries.emplace_back("StringVerifier", new StringVerifier); + doc.entries.emplace_back("TableVerifier", new TableVerifier); // Operator Verifiers - doc.emplace_back("LessDouble", new DoubleLessVerifier(0.0)); - doc.emplace_back("LessInt", new IntLessVerifier(0)); + doc.entries.emplace_back("LessDouble", new DoubleLessVerifier(0.0)); + doc.entries.emplace_back("LessInt", new IntLessVerifier(0)); - doc.emplace_back("LessEqualDouble", new DoubleLessEqualVerifier(0.0)); - doc.emplace_back("LessEqualInt", new IntLessEqualVerifier(0)); + doc.entries.emplace_back("LessEqualDouble", new DoubleLessEqualVerifier(0.0)); + doc.entries.emplace_back("LessEqualInt", new IntLessEqualVerifier(0)); - doc.emplace_back("GreaterDouble", new DoubleGreaterVerifier(0.0)); - doc.emplace_back("GreaterInt", new IntGreaterVerifier(0)); + doc.entries.emplace_back("GreaterDouble", new DoubleGreaterVerifier(0.0)); + doc.entries.emplace_back("GreaterInt", new IntGreaterVerifier(0)); - doc.emplace_back("GreaterEqualDouble", new DoubleGreaterEqualVerifier(0.0)); - doc.emplace_back("GreaterEqualInt", new IntGreaterEqualVerifier(0)); + doc.entries.emplace_back("GreaterEqualDouble", new DoubleGreaterEqualVerifier(0.0)); + doc.entries.emplace_back("GreaterEqualInt", new IntGreaterEqualVerifier(0)); - doc.emplace_back("EqualBool", new BoolEqualVerifier(false)); - doc.emplace_back("EqualDouble", new DoubleEqualVerifier(0.0)); - doc.emplace_back("EqualInt", new IntEqualVerifier(0)); - doc.emplace_back("EqualString", new StringEqualVerifier("")); + doc.entries.emplace_back("EqualBool", new BoolEqualVerifier(false)); + doc.entries.emplace_back("EqualDouble", new DoubleEqualVerifier(0.0)); + doc.entries.emplace_back("EqualInt", new IntEqualVerifier(0)); + doc.entries.emplace_back("EqualString", new StringEqualVerifier("")); - doc.emplace_back("UnequalBool", new BoolUnequalVerifier(false)); - doc.emplace_back("UnequalDouble", new DoubleUnequalVerifier(0.0)); - doc.emplace_back("UnequalInt", new IntUnequalVerifier(0)); - doc.emplace_back("UnequalString", new StringUnequalVerifier("")); + doc.entries.emplace_back("UnequalBool", new BoolUnequalVerifier(false)); + doc.entries.emplace_back("UnequalDouble", new DoubleUnequalVerifier(0.0)); + doc.entries.emplace_back("UnequalInt", new IntUnequalVerifier(0)); + doc.entries.emplace_back("UnequalString", new StringUnequalVerifier("")); // List Verifiers - doc.emplace_back("InListBool", new BoolInListVerifier({ true, false })); - doc.emplace_back("InListDouble", new DoubleInListVerifier({ 0.0, 1.0})); - doc.emplace_back("InListInt", new IntInListVerifier({ 0, 1 })); - doc.emplace_back("InListString", new StringInListVerifier({ "", "a" })); + doc.entries.emplace_back("InListBool", new BoolInListVerifier({ true, false })); + doc.entries.emplace_back("InListDouble", new DoubleInListVerifier({ 0.0, 1.0})); + doc.entries.emplace_back("InListInt", new IntInListVerifier({ 0, 1 })); + doc.entries.emplace_back("InListString", new StringInListVerifier({ "", "a" })); - doc.emplace_back("NotInListBool", new BoolNotInListVerifier({ true, false })); - doc.emplace_back("NotInListDouble", new DoubleNotInListVerifier({ 0.0, 1.0 })); - doc.emplace_back("NotInListInt", new IntNotInListVerifier({ 0, 1 })); - doc.emplace_back("NotInListString", new StringNotInListVerifier({ "", "a" })); + doc.entries.emplace_back("NotInListBool", new BoolNotInListVerifier({ true, false })); + doc.entries.emplace_back("NotInListDouble", new DoubleNotInListVerifier({ 0.0, 1.0 })); + doc.entries.emplace_back("NotInListInt", new IntNotInListVerifier({ 0, 1 })); + doc.entries.emplace_back("NotInListString", new StringNotInListVerifier({ "", "a" })); // Range Verifiers - doc.emplace_back("InListDouble", new DoubleInRangeVerifier({ 0.0, 1.0 })); - doc.emplace_back("InListInt", new IntInRangeVerifier({ 0, 1 })); + doc.entries.emplace_back("InListDouble", new DoubleInRangeVerifier({ 0.0, 1.0 })); + doc.entries.emplace_back("InListInt", new IntInRangeVerifier({ 0, 1 })); - doc.emplace_back("NotInListDouble", new DoubleNotInRangeVerifier({ 0.0, 1.0 })); - doc.emplace_back("NotInListInt", new IntNotInRangeVerifier({ 0, 1 })); + doc.entries.emplace_back("NotInListDouble", new DoubleNotInRangeVerifier({ 0.0, 1.0 })); + doc.entries.emplace_back("NotInListInt", new IntNotInRangeVerifier({ 0, 1 })); // Misc Verifiers - doc.emplace_back("AnnotationBool", new BoolAnnotationVerifier("Bool")); - doc.emplace_back("AnnotationDouble", new DoubleAnnotationVerifier("Double")); - doc.emplace_back("AnnotationInt", new IntAnnotationVerifier("Int")); - doc.emplace_back("AnnotationString", new StringAnnotationVerifier("String")); - doc.emplace_back("AnnotationTable", new TableAnnotationVerifier("Table")); + doc.entries.emplace_back("AnnotationBool", new BoolAnnotationVerifier("Bool")); + doc.entries.emplace_back("AnnotationDouble", new DoubleAnnotationVerifier("Double")); + doc.entries.emplace_back("AnnotationInt", new IntAnnotationVerifier("Int")); + doc.entries.emplace_back("AnnotationString", new StringAnnotationVerifier("String")); + doc.entries.emplace_back("AnnotationTable", new TableAnnotationVerifier("Table")); } TEST_F(DocumentationTest, InitializerConstructor) { using namespace openspace::documentation; - Documentation doc{ - // Basic Verifiers - {"BoolVerifier", new BoolVerifier }, - {"DoubleVerifier", new DoubleVerifier}, - {"IntVerifier", new IntVerifier}, - {"StringVerifier", new StringVerifier}, - {"TableVerifier", new TableVerifier}, + Documentation doc { + "Test", + { + // Basic Verifiers + {"BoolVerifier", new BoolVerifier }, + {"DoubleVerifier", new DoubleVerifier}, + {"IntVerifier", new IntVerifier}, + {"StringVerifier", new StringVerifier}, + {"TableVerifier", new TableVerifier}, - // Operator Verifiers - { "LessDouble", new DoubleLessVerifier(0.0)}, - { "LessInt", new IntLessVerifier(0)}, + // Operator Verifiers + { "LessDouble", new DoubleLessVerifier(0.0)}, + { "LessInt", new IntLessVerifier(0)}, - {"LessEqualDouble", new DoubleLessEqualVerifier(0.0)}, - {"LessEqualInt", new IntLessEqualVerifier(0)}, + {"LessEqualDouble", new DoubleLessEqualVerifier(0.0)}, + {"LessEqualInt", new IntLessEqualVerifier(0)}, - {"GreaterDouble", new DoubleGreaterVerifier(0.0)}, - {"GreaterInt", new IntGreaterVerifier(0)}, + {"GreaterDouble", new DoubleGreaterVerifier(0.0)}, + {"GreaterInt", new IntGreaterVerifier(0)}, - {"GreaterEqualDouble", new DoubleGreaterEqualVerifier(0.0)}, - {"GreaterEqualInt", new IntGreaterEqualVerifier(0)}, + {"GreaterEqualDouble", new DoubleGreaterEqualVerifier(0.0)}, + {"GreaterEqualInt", new IntGreaterEqualVerifier(0)}, - {"EqualBool", new BoolEqualVerifier(false)}, - {"EqualDouble", new DoubleEqualVerifier(0.0)}, - {"EqualInt", new IntEqualVerifier(0)}, - {"EqualString", new StringEqualVerifier("")}, + {"EqualBool", new BoolEqualVerifier(false)}, + {"EqualDouble", new DoubleEqualVerifier(0.0)}, + {"EqualInt", new IntEqualVerifier(0)}, + {"EqualString", new StringEqualVerifier("")}, - {"UnequalBool", new BoolUnequalVerifier(false)}, - {"UnequalDouble", new DoubleUnequalVerifier(0.0)}, - {"UnequalInt", new IntUnequalVerifier(0)}, - {"UnequalString", new StringUnequalVerifier("")}, + {"UnequalBool", new BoolUnequalVerifier(false)}, + {"UnequalDouble", new DoubleUnequalVerifier(0.0)}, + {"UnequalInt", new IntUnequalVerifier(0)}, + {"UnequalString", new StringUnequalVerifier("")}, - // List Verifiers - {"InListBool", new BoolInListVerifier({ true, false })}, - {"InListDouble", new DoubleInListVerifier({ 0.0, 1.0 })}, - {"InListInt", new IntInListVerifier({ 0, 1 })}, - {"InListString", new StringInListVerifier({ "", "a" })}, + // List Verifiers + {"InListBool", new BoolInListVerifier({ true, false })}, + {"InListDouble", new DoubleInListVerifier({ 0.0, 1.0 })}, + {"InListInt", new IntInListVerifier({ 0, 1 })}, + {"InListString", new StringInListVerifier({ "", "a" })}, - {"NotInListBool", new BoolNotInListVerifier({ true, false })}, - {"NotInListDouble", new DoubleNotInListVerifier({ 0.0, 1.0 })}, - {"NotInListInt", new IntNotInListVerifier({ 0, 1 })}, - {"NotInListString", new StringNotInListVerifier({ "", "a" })}, + {"NotInListBool", new BoolNotInListVerifier({ true, false })}, + {"NotInListDouble", new DoubleNotInListVerifier({ 0.0, 1.0 })}, + {"NotInListInt", new IntNotInListVerifier({ 0, 1 })}, + {"NotInListString", new StringNotInListVerifier({ "", "a" })}, - // Range Verifiers - {"InRangeDouble", new DoubleInRangeVerifier(0.0, 1.0)}, - {"InRangeInt", new IntInRangeVerifier(0, 1)}, + // Range Verifiers + {"InRangeDouble", new DoubleInRangeVerifier(0.0, 1.0)}, + {"InRangeInt", new IntInRangeVerifier(0, 1)}, - {"InRangeDouble", new DoubleNotInRangeVerifier(0.0, 1.0)}, - {"InRangeInt", new IntNotInRangeVerifier(0, 1)}, + {"InRangeDouble", new DoubleNotInRangeVerifier(0.0, 1.0)}, + {"InRangeInt", new IntNotInRangeVerifier(0, 1)}, - // Misc Verifiers - {"AnnotationBool", new BoolAnnotationVerifier("Bool")}, - {"AnnotationDouble", new DoubleAnnotationVerifier("Double")}, - {"AnnotationInt", new IntAnnotationVerifier("Int")}, - {"AnnotationString", new StringAnnotationVerifier("String")}, - {"AnnotationTable", new TableAnnotationVerifier("Table")} + // Misc Verifiers + {"AnnotationBool", new BoolAnnotationVerifier("Bool")}, + {"AnnotationDouble", new DoubleAnnotationVerifier("Double")}, + {"AnnotationInt", new IntAnnotationVerifier("Int")}, + {"AnnotationString", new StringAnnotationVerifier("String")}, + {"AnnotationTable", new TableAnnotationVerifier("Table")} + } }; } TEST_F(DocumentationTest, BoolVerifier) { using namespace openspace::documentation; - Documentation doc{ - { "Bool", new BoolVerifier }, + Documentation doc { + "", + {{ "Bool", new BoolVerifier }} }; ghoul::Dictionary positive { @@ -192,7 +196,8 @@ TEST_F(DocumentationTest, DoubleVerifier) { using namespace openspace::documentation; Documentation doc { - { "Double", new DoubleVerifier } + "", + {{ "Double", new DoubleVerifier }} }; ghoul::Dictionary positive { @@ -225,7 +230,8 @@ TEST_F(DocumentationTest, IntVerifier) { using namespace openspace::documentation; Documentation doc { - { "Int", new IntVerifier } + "", + {{ "Int", new IntVerifier }} }; ghoul::Dictionary positive { @@ -265,7 +271,8 @@ TEST_F(DocumentationTest, StringVerifier) { using namespace std::string_literals; Documentation doc { - { "String", new StringVerifier } + "Test", + {{ "String", new StringVerifier }} }; ghoul::Dictionary positive { @@ -296,7 +303,8 @@ TEST_F(DocumentationTest, TableVerifierType) { using namespace openspace::documentation; Documentation doc { - { "Table", new TableVerifier } + "Test", + {{ "Table", new TableVerifier }} }; ghoul::Dictionary positive { @@ -328,11 +336,14 @@ TEST_F(DocumentationTest, MixedVerifiers) { using namespace std::string_literals; Documentation doc { - { "Bool", new BoolVerifier }, - { "Double", new DoubleVerifier }, - { "Int", new IntVerifier }, - { "String", new StringVerifier }, - { "Table", new TableVerifier } + "Test", + { + { "Bool", new BoolVerifier }, + { "Double", new DoubleVerifier }, + { "Int", new IntVerifier }, + { "String", new StringVerifier }, + { "Table", new TableVerifier } + } }; ghoul::Dictionary positive { @@ -377,19 +388,22 @@ TEST_F(DocumentationTest, NestedTables) { using namespace std::string_literals; Documentation doc { - { "Outer_Int", new IntVerifier }, - { "Outer_Table", new TableVerifier({ - { "Inner_Double", new DoubleVerifier }, - { "Inner_String", new StringVerifier } - })}, - { "Outer_Double", new DoubleVerifier }, - { "Outer_Table2" , new TableVerifier({ - { "Inner_Double2", new DoubleVerifier }, - { "Inner_String2", new StringVerifier }, - { "Inner_Table" , new TableVerifier({ - { "Inner_Inner_Int", new IntVerifier } + "Test", + { + { "Outer_Int", new IntVerifier }, + { "Outer_Table", new TableVerifier({ + { "Inner_Double", new DoubleVerifier }, + { "Inner_String", new StringVerifier } + })}, + { "Outer_Double", new DoubleVerifier }, + { "Outer_Table2" , new TableVerifier({ + { "Inner_Double2", new DoubleVerifier }, + { "Inner_String2", new StringVerifier }, + { "Inner_Table" , new TableVerifier({ + { "Inner_Inner_Int", new IntVerifier } + })} })} - })} + } }; ghoul::Dictionary positive { @@ -517,8 +531,11 @@ TEST_F(DocumentationTest, Optional) { using namespace openspace::documentation; Documentation doc { - { "Bool_Force", new BoolVerifier, "", Optional::No }, - { "Bool_Optional", new BoolVerifier, "", Optional::Yes } + "Test", + { + { "Bool_Force", new BoolVerifier, "", Optional::No }, + { "Bool_Optional", new BoolVerifier, "", Optional::Yes } + } }; ghoul::Dictionary positive { @@ -565,7 +582,8 @@ TEST_F(DocumentationTest, RequiredInOptional) { using namespace openspace::documentation; Documentation doc { - { + "Test", + {{ "a", new TableVerifier({ { @@ -581,7 +599,7 @@ TEST_F(DocumentationTest, RequiredInOptional) { }), "", Optional::Yes - } + }} }; ghoul::Dictionary positive { @@ -625,7 +643,8 @@ TEST_F(DocumentationTest, LessInt) { using namespace openspace::documentation; Documentation doc { - { "Int", new IntLessVerifier(5) } + "Test", + {{ "Int", new IntLessVerifier(5) }} }; ghoul::Dictionary positive { @@ -648,7 +667,8 @@ TEST_F(DocumentationTest, LessDouble) { using namespace openspace::documentation; Documentation doc { - { "Double", new DoubleLessVerifier(5.0) } + "Test", + {{ "Double", new DoubleLessVerifier(5.0) }} }; ghoul::Dictionary positive { @@ -671,7 +691,8 @@ TEST_F(DocumentationTest, LessEqualInt) { using namespace openspace::documentation; Documentation doc { - { "Int", new IntLessEqualVerifier(5) } + "Test", + {{ "Int", new IntLessEqualVerifier(5) }} }; ghoul::Dictionary positive { @@ -701,7 +722,8 @@ TEST_F(DocumentationTest, LessEqualDouble) { using namespace openspace::documentation; Documentation doc { - { "Double", new DoubleLessEqualVerifier(5.0) } + "Test", + {{ "Double", new DoubleLessEqualVerifier(5.0) }} }; ghoul::Dictionary positive { @@ -731,7 +753,8 @@ TEST_F(DocumentationTest, GreaterInt) { using namespace openspace::documentation; Documentation doc { - { "Int", new IntGreaterVerifier(5) } + "Test", + {{ "Int", new IntGreaterVerifier(5) }} }; ghoul::Dictionary positive { @@ -754,7 +777,8 @@ TEST_F(DocumentationTest, GreaterDouble) { using namespace openspace::documentation; Documentation doc { - { "Double", new DoubleGreaterVerifier(5.0) } + "Test", + {{ "Double", new DoubleGreaterVerifier(5.0) }} }; ghoul::Dictionary positive { @@ -777,7 +801,8 @@ TEST_F(DocumentationTest, GreaterEqualInt) { using namespace openspace::documentation; Documentation doc { - { "Int", new IntGreaterEqualVerifier(5) } + "Test", + {{ "Int", new IntGreaterEqualVerifier(5) }} }; ghoul::Dictionary positive { @@ -807,7 +832,8 @@ TEST_F(DocumentationTest, GreaterEqualDouble) { using namespace openspace::documentation; Documentation doc { - { "Double", new DoubleGreaterEqualVerifier(5.0) } + "Test", + {{ "Double", new DoubleGreaterEqualVerifier(5.0) }} }; ghoul::Dictionary positive { @@ -838,7 +864,8 @@ TEST_F(DocumentationTest, EqualBool) { using namespace openspace::documentation; Documentation doc { - { "Bool", new BoolEqualVerifier(true) } + "Test", + {{ "Bool", new BoolEqualVerifier(true) }} }; ghoul::Dictionary positive { @@ -861,7 +888,8 @@ TEST_F(DocumentationTest, EqualInt) { using namespace openspace::documentation; Documentation doc { - { "Int", new IntEqualVerifier(1) } + "Test", + {{ "Int", new IntEqualVerifier(1) }} }; ghoul::Dictionary positive { @@ -884,7 +912,8 @@ TEST_F(DocumentationTest, EqualDouble) { using namespace openspace::documentation; Documentation doc { - { "Double", new DoubleEqualVerifier(1.0) } + "Test", + {{ "Double", new DoubleEqualVerifier(1.0) }} }; ghoul::Dictionary positive { @@ -908,7 +937,8 @@ TEST_F(DocumentationTest, EqualString) { using namespace std::string_literals; Documentation doc { - { "String", new StringEqualVerifier("string"s) } + "Test", + {{ "String", new StringEqualVerifier("string"s) }} }; ghoul::Dictionary positive { @@ -931,7 +961,8 @@ TEST_F(DocumentationTest, UnequalBool) { using namespace openspace::documentation; Documentation doc { - { "Bool", new BoolUnequalVerifier(true) } + "Test", + {{ "Bool", new BoolUnequalVerifier(true) }} }; ghoul::Dictionary positive { @@ -954,7 +985,8 @@ TEST_F(DocumentationTest, UnequalInt) { using namespace openspace::documentation; Documentation doc { - { "Int", new IntUnequalVerifier(1) } + "Test", + {{ "Int", new IntUnequalVerifier(1) }} }; ghoul::Dictionary positive { @@ -977,7 +1009,8 @@ TEST_F(DocumentationTest, UnequalDouble) { using namespace openspace::documentation; Documentation doc { - { "Double", new DoubleUnequalVerifier(1.0) } + "Test", + {{ "Double", new DoubleUnequalVerifier(1.0) }} }; ghoul::Dictionary positive { @@ -1001,7 +1034,8 @@ TEST_F(DocumentationTest, UnequalString) { using namespace std::string_literals; Documentation doc { - { "String", new StringUnequalVerifier("string"s) } + "Test", + {{ "String", new StringUnequalVerifier("string"s) }} }; ghoul::Dictionary positive { @@ -1024,7 +1058,8 @@ TEST_F(DocumentationTest, ListBool) { using namespace openspace::documentation; Documentation doc { - { "Bool" , new BoolInListVerifier({ true }) } + "Test", + {{ "Bool" , new BoolInListVerifier({ true }) }} }; ghoul::Dictionary positive { @@ -1047,7 +1082,8 @@ TEST_F(DocumentationTest, ListInt) { using namespace openspace::documentation; Documentation doc { - { "Int" , new IntInListVerifier({ 0, 1, 2 }) } + "Test", + {{ "Int" , new IntInListVerifier({ 0, 1, 2 }) }} }; ghoul::Dictionary positive { @@ -1077,7 +1113,8 @@ TEST_F(DocumentationTest, ListDouble) { using namespace openspace::documentation; Documentation doc { - { "Double" , new DoubleInListVerifier({ 0.0, 1.0, 2.0 }) } + "Test", + {{ "Double" , new DoubleInListVerifier({ 0.0, 1.0, 2.0 }) }} }; ghoul::Dictionary positive { @@ -1108,7 +1145,8 @@ TEST_F(DocumentationTest, ListString) { using namespace std::string_literals; Documentation doc { - { "String" , new StringInListVerifier({ "0"s, "1"s, "2"s }) } + "Test", + {{ "String" , new StringInListVerifier({ "0"s, "1"s, "2"s }) }} }; ghoul::Dictionary positive { @@ -1138,7 +1176,8 @@ TEST_F(DocumentationTest, NotListBool) { using namespace openspace::documentation; Documentation doc { - { "Bool" , new BoolNotInListVerifier({ true }) } + "Test", + {{ "Bool" , new BoolNotInListVerifier({ true }) }} }; ghoul::Dictionary positive { @@ -1161,7 +1200,8 @@ TEST_F(DocumentationTest, NotListInt) { using namespace openspace::documentation; Documentation doc { - { "Int" , new IntNotInListVerifier({ 0, 1, 2 }) } + "Test", + {{ "Int" , new IntNotInListVerifier({ 0, 1, 2 }) }} }; ghoul::Dictionary positive { @@ -1191,7 +1231,8 @@ TEST_F(DocumentationTest, NotListDouble) { using namespace openspace::documentation; Documentation doc { - { "Double" , new DoubleNotInListVerifier({ 0.0, 1.0, 2.0 }) } + "Test", + {{ "Double" , new DoubleNotInListVerifier({ 0.0, 1.0, 2.0 }) }} }; ghoul::Dictionary positive { @@ -1222,7 +1263,8 @@ TEST_F(DocumentationTest, NotListString) { using namespace std::string_literals; Documentation doc { - { "String" , new StringNotInListVerifier({ "0"s, "1"s, "2"s }) } + "Test", + {{ "String" , new StringNotInListVerifier({ "0"s, "1"s, "2"s }) }} }; ghoul::Dictionary positive { @@ -1252,7 +1294,8 @@ TEST_F(DocumentationTest, AnnotationBool) { using namespace openspace::documentation; Documentation doc { - { "Bool", new BoolAnnotationVerifier("Bool") } + "Test", + {{ "Bool", new BoolAnnotationVerifier("Bool") }} }; ghoul::Dictionary positive { @@ -1275,7 +1318,8 @@ TEST_F(DocumentationTest, AnnotationInt) { using namespace openspace::documentation; Documentation doc { - { "Int", new IntAnnotationVerifier("Int") } + "Test", + {{ "Int", new IntAnnotationVerifier("Int") }} }; ghoul::Dictionary positive { @@ -1298,7 +1342,8 @@ TEST_F(DocumentationTest, AnnotationDouble) { using namespace openspace::documentation; Documentation doc { - { "Double", new DoubleAnnotationVerifier("Double") } + "Test", + {{ "Double", new DoubleAnnotationVerifier("Double") }} }; ghoul::Dictionary positive { @@ -1322,7 +1367,8 @@ TEST_F(DocumentationTest, AnnotationString) { using namespace std::string_literals; Documentation doc { - { "String", new StringAnnotationVerifier("String") } + "Test", + {{ "String", new StringAnnotationVerifier("String") }} }; ghoul::Dictionary positive { @@ -1345,7 +1391,8 @@ TEST_F(DocumentationTest, AnnotationTable) { using namespace openspace::documentation; Documentation doc { - { "Table", new TableAnnotationVerifier("Table") } + "Test", + {{ "Table", new TableAnnotationVerifier("Table") }} }; ghoul::Dictionary positive { @@ -1368,7 +1415,8 @@ TEST_F(DocumentationTest, InRangeInt) { using namespace openspace::documentation; Documentation doc { - { "Int", new InRangeVerifier(0, 5) } + "Test", + {{ "Int", new InRangeVerifier(0, 5) }} }; ghoul::Dictionary positive { @@ -1405,7 +1453,8 @@ TEST_F(DocumentationTest, InRangeDouble) { using namespace openspace::documentation; Documentation doc { - { "Double", new InRangeVerifier(0.0, 5.0) } + "Test", + {{ "Double", new InRangeVerifier(0.0, 5.0) }} }; ghoul::Dictionary positive { @@ -1449,7 +1498,8 @@ TEST_F(DocumentationTest, NotInRangeInt) { using namespace openspace::documentation; Documentation doc { - { "Int", new NotInRangeVerifier(0, 5) } + "Test", + {{ "Int", new NotInRangeVerifier(0, 5) }} }; ghoul::Dictionary positive { @@ -1495,7 +1545,8 @@ TEST_F(DocumentationTest, NotInRangeDouble) { using namespace openspace::documentation; Documentation doc { - { "Double", new NotInRangeVerifier(0.0, 5.0) } + "Test", + {{ "Double", new NotInRangeVerifier(0.0, 5.0) }} }; ghoul::Dictionary positive { @@ -1541,7 +1592,8 @@ TEST_F(DocumentationTest, Wildcard) { using namespace openspace::documentation; Documentation doc { - { "*", new IntVerifier } + "Test", + {{ "*", new IntVerifier }} }; ghoul::Dictionary positive { @@ -1591,8 +1643,11 @@ TEST_F(DocumentationTest, WildcardMixed) { using namespace openspace::documentation; Documentation doc { - { "*", new IntVerifier }, - { "b", new IntGreaterVerifier(5) } + "Test", + { + { "*", new IntVerifier }, + { "b", new IntGreaterVerifier(5) } + } }; ghoul::Dictionary positive { @@ -1654,9 +1709,12 @@ TEST_F(DocumentationTest, AndOperator) { using namespace openspace::documentation; Documentation doc { - { "a", new AndVerifier( - new IntGreaterEqualVerifier(2), new IntLessEqualVerifier(5) - ) + "Test", + { + { "a", new AndVerifier( + new IntGreaterEqualVerifier(2), new IntLessEqualVerifier(5) + ) + } } }; @@ -1689,7 +1747,8 @@ TEST_F(DocumentationTest, OrOperator) { using namespace std::string_literals; Documentation doc { - { "a", new OrVerifier(new StringVerifier, new IntVerifier)} + "Test", + {{ "a", new OrVerifier(new StringVerifier, new IntVerifier)}} }; ghoul::Dictionary positive { From 9afae5c2f9e5f23d2008a4820621d3b69d849da4 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 15 Sep 2016 09:19:46 +0200 Subject: [PATCH 59/92] Remove extra includes --- modules/debugging/rendering/renderabledebugplane.cpp | 2 -- modules/newhorizons/rendering/renderablecrawlingline.cpp | 2 -- 2 files changed, 4 deletions(-) diff --git a/modules/debugging/rendering/renderabledebugplane.cpp b/modules/debugging/rendering/renderabledebugplane.cpp index da2378fee1..98077c7a7b 100644 --- a/modules/debugging/rendering/renderabledebugplane.cpp +++ b/modules/debugging/rendering/renderabledebugplane.cpp @@ -26,8 +26,6 @@ #include - -#include #include #include diff --git a/modules/newhorizons/rendering/renderablecrawlingline.cpp b/modules/newhorizons/rendering/renderablecrawlingline.cpp index 34f07bd365..4c538c180a 100644 --- a/modules/newhorizons/rendering/renderablecrawlingline.cpp +++ b/modules/newhorizons/rendering/renderablecrawlingline.cpp @@ -24,12 +24,10 @@ #include -#include #include #include #include #include -//#include namespace { const std::string _loggerCat = "RenderableCrawlingLine"; From 2693b0102e673ab443a74daaa4898d59a998570f Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 15 Sep 2016 10:38:11 +0200 Subject: [PATCH 60/92] Add VectorVerifiers to check against glm::ivecX, glm::dvecX, and glm::bvecX --- include/openspace/documentation/verifier.h | 48 +++ include/openspace/documentation/verifier.inl | 36 +++ src/documentation/verifier.cpp | 10 + tests/test_documentation.inl | 290 ++++++++++++++++++- 4 files changed, 383 insertions(+), 1 deletion(-) diff --git a/include/openspace/documentation/verifier.h b/include/openspace/documentation/verifier.h index 533c7e992a..d6ca25dac4 100644 --- a/include/openspace/documentation/verifier.h +++ b/include/openspace/documentation/verifier.h @@ -79,6 +79,29 @@ struct TableVerifier : public TemplateVerifier { std::vector doc; }; +struct VectorVerifier {}; + +template +struct Vector2Verifier : public TemplateVerifier>, public VectorVerifier { + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + + std::string documentation() const override; +}; + +template +struct Vector3Verifier : public TemplateVerifier>, public VectorVerifier { + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + + std::string documentation() const override; +}; + +template +struct Vector4Verifier : public TemplateVerifier>, public VectorVerifier { + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + + std::string documentation() const override; +}; + // Operator Verifiers template @@ -86,6 +109,7 @@ struct LessVerifier : public T { static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); LessVerifier(typename T::Type value); @@ -101,6 +125,7 @@ struct LessEqualVerifier : public T { static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); LessEqualVerifier(typename T::Type value); @@ -116,6 +141,7 @@ struct GreaterVerifier : public T { static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); GreaterVerifier(typename T::Type value); @@ -131,6 +157,7 @@ struct GreaterEqualVerifier : public T { static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); GreaterEqualVerifier(typename T::Type value); @@ -201,6 +228,7 @@ struct InRangeVerifier : public T { static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); InRangeVerifier(typename T::Type lower, typename T::Type upper); @@ -217,6 +245,7 @@ struct NotInRangeVerifier : public T { static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); NotInRangeVerifier(typename T::Type lower, typename T::Type upper); @@ -265,6 +294,16 @@ struct OrVerifier : public Verifier { std::shared_ptr b; }; +using BoolVector2Verifier = Vector2Verifier; +using IntVector2Verifier = Vector2Verifier; +using DoubleVector2Verifier = Vector2Verifier; +using BoolVector3Verifier = Vector3Verifier; +using IntVector3Verifier = Vector3Verifier; +using DoubleVector3Verifier = Vector3Verifier; +using BoolVector4Verifier = Vector4Verifier; +using IntVector4Verifier = Vector4Verifier; +using DoubleVector4Verifier = Vector4Verifier; + using IntLessVerifier = LessVerifier; using DoubleLessVerifier = LessVerifier; using IntLessEqualVerifier = LessEqualVerifier; @@ -302,6 +341,15 @@ using DoubleAnnotationVerifier = AnnotationVerifier; using StringAnnotationVerifier = AnnotationVerifier; using TableAnnotationVerifier = AnnotationVerifier; +extern template struct Vector2Verifier; +extern template struct Vector2Verifier; +extern template struct Vector2Verifier; +extern template struct Vector3Verifier; +extern template struct Vector3Verifier; +extern template struct Vector3Verifier; +extern template struct Vector4Verifier; +extern template struct Vector4Verifier; +extern template struct Vector4Verifier; extern template struct LessVerifier; extern template struct LessVerifier; diff --git a/include/openspace/documentation/verifier.inl b/include/openspace/documentation/verifier.inl index c2b8f0d02d..040a0b09e7 100644 --- a/include/openspace/documentation/verifier.inl +++ b/include/openspace/documentation/verifier.inl @@ -31,6 +31,42 @@ std::string to_string(std::string value); namespace openspace { namespace documentation { +template +bool Vector2Verifier::test(const ghoul::Dictionary& d, const std::string& k) const { + return d.hasKeyAndValue>(k); +} + +template +std::string Vector2Verifier::documentation() const { + using namespace std::string_literals; + + return "Type: Vector2<"s + typeid(T).name() + ">"; +} + +template +bool Vector3Verifier::test(const ghoul::Dictionary& d, const std::string& k) const { + return d.hasKeyAndValue>(k); +} + +template +std::string Vector3Verifier::documentation() const { + using namespace std::string_literals; + + return "Type: Vector3<"s + typeid(T).name() + ">"; +} + +template +bool Vector4Verifier::test(const ghoul::Dictionary& d, const std::string& k) const { + return d.hasKeyAndValue>(k); +} + +template +std::string Vector4Verifier::documentation() const { + using namespace std::string_literals; + + return "Type: Vector4<"s + typeid(T).name() + ">"; +} + template LessVerifier::LessVerifier(typename T::Type value) : value(std::move(value)) diff --git a/src/documentation/verifier.cpp b/src/documentation/verifier.cpp index 4c8a8a2543..8e8c04e850 100644 --- a/src/documentation/verifier.cpp +++ b/src/documentation/verifier.cpp @@ -27,6 +27,16 @@ namespace openspace { namespace documentation { +template struct Vector2Verifier; +template struct Vector2Verifier; +template struct Vector2Verifier; +template struct Vector3Verifier; +template struct Vector3Verifier; +template struct Vector3Verifier; +template struct Vector4Verifier; +template struct Vector4Verifier; +template struct Vector4Verifier; + template struct LessVerifier; template struct LessVerifier; template struct LessEqualVerifier; diff --git a/tests/test_documentation.inl b/tests/test_documentation.inl index 9ddc0efda4..773088cad8 100644 --- a/tests/test_documentation.inl +++ b/tests/test_documentation.inl @@ -1752,7 +1752,7 @@ TEST_F(DocumentationTest, OrOperator) { }; ghoul::Dictionary positive { - { "a", ""s} + { "a", ""s } }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); @@ -1773,3 +1773,291 @@ TEST_F(DocumentationTest, OrOperator) { ASSERT_EQ(1, negativeRes.offenders.size()); EXPECT_EQ("a", negativeRes.offenders[0]); } + +TEST_F(DocumentationTest, BoolVector2Verifier) { + using namespace openspace::documentation; + + Documentation doc { + "Test", + {{ "a", new BoolVector2Verifier }} + }; + + ghoul::Dictionary positive { + { "a", glm::bvec2(true) } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "a", ghoul::Dictionary{ {"1", true}, {"2", 1.0} } } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("a", negativeRes.offenders[0]); + + ghoul::Dictionary negative2 { + { "a", true } + }; + negativeRes = testSpecification(doc, negative2); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("a", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, IntVector2Verifier) { + using namespace openspace::documentation; + + Documentation doc { + "Test", + { { "a", new IntVector2Verifier } } + }; + + ghoul::Dictionary positive { + { "a", glm::ivec2(2) } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "a", ghoul::Dictionary{ { "1", true },{ "2", 1 } } } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("a", negativeRes.offenders[0]); + + ghoul::Dictionary negative2 { + { "a", true } + }; + negativeRes = testSpecification(doc, negative2); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("a", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, DoubleVector2Verifier) { + using namespace openspace::documentation; + + Documentation doc{ + "Test", + { { "a", new DoubleVector2Verifier } } + }; + + ghoul::Dictionary positive { + { "a", glm::dvec2(2.0) } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "a", ghoul::Dictionary{ { "1", true }, { "2", 1.0 } } } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("a", negativeRes.offenders[0]); + + ghoul::Dictionary negative2 { + { "a", true } + }; + negativeRes = testSpecification(doc, negative2); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("a", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, BoolVector3Verifier) { + using namespace openspace::documentation; + + Documentation doc { + "Test", + { { "a", new BoolVector3Verifier } } + }; + + ghoul::Dictionary positive { + { "a", glm::bvec3(true) } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "a", ghoul::Dictionary{ { "1", true },{ "2", 1.0 }, { "3", "s" } } } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("a", negativeRes.offenders[0]); + + ghoul::Dictionary negative2 { + { "a", true } + }; + negativeRes = testSpecification(doc, negative2); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("a", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, IntVector3Verifier) { + using namespace openspace::documentation; + + Documentation doc { + "Test", + { { "a", new IntVector3Verifier } } + }; + + ghoul::Dictionary positive { + { "a", glm::ivec3(2) } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "a", ghoul::Dictionary{ { "1", true },{ "2", 1 }, { "3", "s" } } } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("a", negativeRes.offenders[0]); + + ghoul::Dictionary negative2 { + { "a", true } + }; + negativeRes = testSpecification(doc, negative2); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("a", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, DoubleVector3Verifier) { + using namespace openspace::documentation; + + Documentation doc { + "Test", + { { "a", new DoubleVector3Verifier } } + }; + + ghoul::Dictionary positive { + { "a", glm::dvec3(2.0) } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "a", ghoul::Dictionary{ { "1", true },{ "2", 1.0 }, { "3", "s"} } } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("a", negativeRes.offenders[0]); + + ghoul::Dictionary negative2 { + { "a", true } + }; + negativeRes = testSpecification(doc, negative2); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("a", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, BoolVector4Verifier) { + using namespace openspace::documentation; + + Documentation doc { + "Test", + { { "a", new BoolVector4Verifier } } + }; + + ghoul::Dictionary positive { + { "a", glm::bvec4(true) } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "a", ghoul::Dictionary{ { "1", true },{ "2", 1.0 }, { "3", "s" }, { "4", 1 }}} + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("a", negativeRes.offenders[0]); + + ghoul::Dictionary negative2 { + { "a", true } + }; + negativeRes = testSpecification(doc, negative2); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("a", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, IntVector4Verifier) { + using namespace openspace::documentation; + + Documentation doc { + "Test", + { { "a", new IntVector4Verifier } } + }; + + ghoul::Dictionary positive { + { "a", glm::ivec4(2) } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "a", ghoul::Dictionary{ { "1", true },{ "2", 1 },{ "3", "s" }, { "4", 1 } } } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("a", negativeRes.offenders[0]); + + ghoul::Dictionary negative2{ + { "a", true } + }; + negativeRes = testSpecification(doc, negative2); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("a", negativeRes.offenders[0]); +} + +TEST_F(DocumentationTest, DoubleVector4Verifier) { + using namespace openspace::documentation; + + Documentation doc { + "Test", + { { "a", new DoubleVector4Verifier } } + }; + + ghoul::Dictionary positive { + { "a", glm::dvec4(2.0) } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "a", ghoul::Dictionary{ { "1", true },{ "2", 1.0 },{ "3", "s" }, { "4", 1 } } } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("a", negativeRes.offenders[0]); + + ghoul::Dictionary negative2 { + { "a", true } + }; + negativeRes = testSpecification(doc, negative2); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenders.size()); + EXPECT_EQ("a", negativeRes.offenders[0]); +} From 989e40395ea97bb456dfa597e9d966738ac242c0 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 15 Sep 2016 10:39:11 +0200 Subject: [PATCH 61/92] Add documentation to scene description files Check incoming scene files against the documentation/specification --- include/openspace/scene/scene.h | 4 + src/CMakeLists.txt | 1 + src/engine/configurationmanager_doc.inl | 324 ++++++++++++------------ src/scene/scene.cpp | 13 +- src/scene/scene_doc.inl | 94 +++++++ 5 files changed, 273 insertions(+), 163 deletions(-) create mode 100644 src/scene/scene_doc.inl diff --git a/include/openspace/scene/scene.h b/include/openspace/scene/scene.h index 4844d3ac7b..622ef1f6e1 100644 --- a/include/openspace/scene/scene.h +++ b/include/openspace/scene/scene.h @@ -31,6 +31,8 @@ #include #include +#include + #include #include #include @@ -117,6 +119,8 @@ public: */ static scripting::LuaLibrary luaLibrary(); + static Documentation Documentation(); + private: bool loadSceneInternal(const std::string& sceneDescriptionFilePath); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0f2b331c39..c81f3999cc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -81,6 +81,7 @@ set(OPENSPACE_SOURCE ${OPENSPACE_BASE_DIR}/src/scene/rotation.cpp ${OPENSPACE_BASE_DIR}/src/scene/scale.cpp ${OPENSPACE_BASE_DIR}/src/scene/scene.cpp + ${OPENSPACE_BASE_DIR}/src/scene/scene_doc.inl ${OPENSPACE_BASE_DIR}/src/scene/scene_lua.inl ${OPENSPACE_BASE_DIR}/src/scene/scenegraph.cpp ${OPENSPACE_BASE_DIR}/src/scene/scenegraphnode.cpp diff --git a/src/engine/configurationmanager_doc.inl b/src/engine/configurationmanager_doc.inl index 0203090f86..69977b3bee 100644 --- a/src/engine/configurationmanager_doc.inl +++ b/src/engine/configurationmanager_doc.inl @@ -30,7 +30,7 @@ Documentation ConfigurationManager::Documentation() { using namespace documentation; return { - "ConfigurationManager", + "OpenSpace Configuration", { { "SGCTConfig", @@ -101,176 +101,176 @@ Documentation ConfigurationManager::Documentation() { { "Type", new StringInListVerifier({ - // List from logfactory.cpp::createLog - "text", "html" - }), - "The type of the new log to be generated." -}, -{ - "FileName", - new StringVerifier, - "The filename to which the log will be written." -}, -{ - "Append", - new BoolVerifier, - "Determines whether the file will be cleared at " - "startup or if the contents will be appended to " - "previous runs.", - Optional::Yes -} -}), -"Additional log files", -Optional::Yes -} -}), -"Per default, log messages are written to the console, the " - "onscreen text, and (if available) the Visual Studio output " - "window. This table can define other logging methods that will " - "be used additionally.", - Optional::Yes -}, -{ - "CapabilitiesVerbosity", - new StringInListVerifier( - // List from OpenspaceEngine::initialize - { "None", "Minimal", "Default", "Full" } - ), - "At startup, a list of system capabilities is created and logged." - "This value determines how verbose this listing should be.", - Optional::Yes -} -}), -"Configurations for the logging of messages that are generated " -"throughout the code and are useful for debugging potential errors or " -"other information.", -Optional::Yes -}, -{ - "LuaDocumentationFile", - new TableVerifier({ - { - "Type", - new StringInListVerifier( - // List from ScriptEngine::writeDocumentation - { "text", "html" } - ), - "The type of documentation that will be written." + // List from logfactory.cpp::createLog + "text", "html" + }), + "The type of the new log to be generated." + }, + { + "FileName", + new StringVerifier, + "The filename to which the log will be written." + }, + { + "Append", + new BoolVerifier, + "Determines whether the file will be cleared at " + "startup or if the contents will be appended to " + "previous runs.", + Optional::Yes + } + }), + "Additional log files", + Optional::Yes + } + }), + "Per default, log messages are written to the console, the " + "onscreen text, and (if available) the Visual Studio output " + "window. This table can define other logging methods that will " + "be used additionally.", + Optional::Yes + }, + { + "CapabilitiesVerbosity", + new StringInListVerifier( + // List from OpenspaceEngine::initialize + { "None", "Minimal", "Default", "Full" } + ), + "At startup, a list of system capabilities is created and logged." + "This value determines how verbose this listing should be.", + Optional::Yes + } + }), + "Configurations for the logging of messages that are generated " + "throughout the code and are useful for debugging potential errors or " + "other information.", + Optional::Yes }, { - "File", - new StringVerifier, - "The filename that will be created on startup containing the " - "documentation of available Lua functions. Any existing file " - "will be silently overwritten." - } - }), - "Descriptions of whether and where to create a documentation file that " - "describes the available Lua functions that can be executed in scene " - "files or per console.", - Optional::Yes -}, -{ - "PropertyDocumentationFile", - new TableVerifier({ - { - "Type", - new StringInListVerifier( - // List taken from Scene::writePropertyDocumentation - { "text", "html" } - ), - "The type of property documentation file that is created." + "LuaDocumentationFile", + new TableVerifier({ + { + "Type", + new StringInListVerifier( + // List from ScriptEngine::writeDocumentation + { "text", "html" } + ), + "The type of documentation that will be written." + }, + { + "File", + new StringVerifier, + "The filename that will be created on startup containing the " + "documentation of available Lua functions. Any existing file " + "will be silently overwritten." + } + }), + "Descriptions of whether and where to create a documentation file that " + "describes the available Lua functions that can be executed in scene " + "files or per console.", + Optional::Yes }, { - "File", - new StringVerifier, - "The file that will be created on startup containing a list of " - "all properties in the scene. Any existing file will be silently " - "overwritten." - } - }), - "Descriptions of whether and where to create a list of all properties " - "that were created in the current scene.", - Optional::Yes -}, -{ - "ScriptLogFile", - new TableVerifier({ - { - "Type", - new StringInListVerifier( - // List taken from ScriptEngine::writeLog - { "text" } - ), - "The type of logfile that will be created." + "PropertyDocumentationFile", + new TableVerifier({ + { + "Type", + new StringInListVerifier( + // List taken from Scene::writePropertyDocumentation + { "text", "html" } + ), + "The type of property documentation file that is created." + }, + { + "File", + new StringVerifier, + "The file that will be created on startup containing a list of " + "all properties in the scene. Any existing file will be silently " + "overwritten." + } + }), + "Descriptions of whether and where to create a list of all properties " + "that were created in the current scene.", + Optional::Yes }, { - "File", - new StringVerifier, - "The file that will be created on startup containing the log of " - "all Lua scripts that are executed. Any existing file (including " - "the results from previous runs) will be silently overwritten." - } - }), - "Contains a log of all Lua scripts that were executed in the last " - "session.", - Optional::Yes -}, -{ - "KeyboardShortcuts", - new TableVerifier({ - { - "Type", - new StringInListVerifier( - // List from InteractionHandler::writeKeyboardDocumentation - { "text", "html" } - ), - "The type of keyboard binding documentation that should be " - "written." + "ScriptLogFile", + new TableVerifier({ + { + "Type", + new StringInListVerifier( + // List taken from ScriptEngine::writeLog + { "text" } + ), + "The type of logfile that will be created." + }, + { + "File", + new StringVerifier, + "The file that will be created on startup containing the log of " + "all Lua scripts that are executed. Any existing file (including " + "the results from previous runs) will be silently overwritten." + } + }), + "Contains a log of all Lua scripts that were executed in the last " + "session.", + Optional::Yes }, { - "File", - new StringVerifier, - "The file that will be created on startup containing the list of " - "all keyboard bindings with their respective Lua scripts." + "KeyboardShortcuts", + new TableVerifier({ + { + "Type", + new StringInListVerifier( + // List from InteractionHandler::writeKeyboardDocumentation + { "text", "html" } + ), + "The type of keyboard binding documentation that should be " + "written." + }, + { + "File", + new StringVerifier, + "The file that will be created on startup containing the list of " + "all keyboard bindings with their respective Lua scripts." + } + }), + "Contains the collection of all keyboard shortcuts that were collected " + "during startup. For each key, it mentions which scripts will be " + "executed in the current session.", + Optional::Yes + }, + { + "ShutdownCountdown", + new DoubleGreaterEqualVerifier(0.0), + "The countdown that the application will wait between pressing ESC and " + "actually shutting down. If ESC is pressed again in this time, the " + "shutdown is aborted.", + Optional::Yes + }, + { + "DownloadRequestURL", + new OrVerifier( + new StringVerifier, + new TableVerifier({ + { "*", new StringVerifier } + }) + ), + "The URL from which files will be downloaded by the Launcher. This can " + "either be a single URL or a list of possible URLs from which the " + "Launcher can then choose.", + Optional::Yes + }, + { + "RenderingMethod", + new StringInListVerifier( + // List from RenderEngine::setRendererFromString + { "Framebuffer", "ABuffer" } + ), + "The renderer that is use after startup. The renderer 'ABuffer' requires " + "support for at least OpenGL 4.3", + Optional::Yes } - }), - "Contains the collection of all keyboard shortcuts that were collected " - "during startup. For each key, it mentions which scripts will be " - "executed in the current session.", - Optional::Yes -}, -{ - "ShutdownCountdown", - new DoubleGreaterEqualVerifier(0.0), - "The countdown that the application will wait between pressing ESC and " - "actually shutting down. If ESC is pressed again in this time, the " - "shutdown is aborted.", - Optional::Yes -}, -{ - "DownloadRequestURL", - new OrVerifier( - new StringVerifier, - new TableVerifier({ - { "*", new StringVerifier } - }) - ), - "The URL from which files will be downloaded by the Launcher. This can " - "either be a single URL or a list of possible URLs from which the " - "Launcher can then choose.", - Optional::Yes -}, -{ - "RenderingMethod", - new StringInListVerifier( - // List from RenderEngine::setRendererFromString - { "Framebuffer", "ABuffer" } - ), - "The renderer that is use after startup. The renderer 'ABuffer' requires " - "support for at least OpenGL 4.3", - Optional::Yes -} } }; }; diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp index 300f2d856b..7181a1d49d 100644 --- a/src/scene/scene.cpp +++ b/src/scene/scene.cpp @@ -55,12 +55,12 @@ #include #endif +#include "scene_doc.inl" #include "scene_lua.inl" namespace { const std::string _loggerCat = "Scene"; const std::string _moduleExtension = ".mod"; - const std::string _defaultCommonDirectory = "common"; const std::string _commonModuleToken = "${COMMON_MODULE}"; const std::string KeyCamera = "Camera"; @@ -189,6 +189,17 @@ bool Scene::loadSceneInternal(const std::string& sceneDescriptionFilePath) { state ); + // Perform testing against the documentation/specification + using namespace openspace::documentation; + TestResult result = testSpecification( + Scene::Documentation(), + dictionary + ); + if (!result.success) { + throw SpecificationError(result, "Scene"); + } + + _graph.loadFromFile(sceneDescriptionFilePath); // Initialize all nodes diff --git a/src/scene/scene_doc.inl b/src/scene/scene_doc.inl new file mode 100644 index 0000000000..abd9c145e8 --- /dev/null +++ b/src/scene/scene_doc.inl @@ -0,0 +1,94 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +namespace openspace { + +Documentation Scene::Documentation() { + using namespace documentation; + + return{ + "Scene Description", + { + { + "ScenePath", + new StringVerifier, + "The path to the base directory of the scene. The path is considered " + "relative to the location of the scene description file.", + Optional::Yes + }, + { + "CommonFolder", + new StringAnnotationVerifier("A valid scene module folder"), + "The path to the common folder that is loaded and will be bound to the " + "${COMMON_MODULE} path token so that assets can be reused easily.", + Optional::Yes + }, + { + "Camera", + new TableVerifier({ + { + "Focus", + new StringAnnotationVerifier("A valid object in the scene"), + "The initial focus node of the camera, i.e., the node around which " + "the interaction will be performed." + }, + { + "Position", + new DoubleVector3Verifier, + "The initial camera positive relative to the focus object.", + Optional::Yes + }, + { + "Rotation", + new DoubleVector4Verifier, + "The initial camera rotation expressed as a quaternion.", + Optional::Yes + } + }), + "Definitions of the camera starting parameters, such as focus, location, and " + "orientation.", + Optional::Yes + }, + { + "Modules", + new TableVerifier({ + { "*", new StringAnnotationVerifier( + "Loadable module folders. This means that they either have to point " + "to a folder that contains a ModuleFile or a folder which contains " + "other folders that eventually contain ModuleFile. This second " + "recursive approach is useful for grouping modules into logical " + "units." + )} + }), + "This is the list of modules that will be loaded into the initial scene. The " + "values in this table have to correspond to folders relative to the " + "ScenePath key." + } + } + }; +} + +} // namespace openspace From 1da148c8bea8376e5e156ef9ed53159b9a72e2c6 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 15 Sep 2016 13:27:44 +0200 Subject: [PATCH 62/92] Fix Interactionhandler output file --- src/interaction/interactionhandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/interaction/interactionhandler.cpp b/src/interaction/interactionhandler.cpp index 219461ed84..8f8d389c09 100644 --- a/src/interaction/interactionhandler.cpp +++ b/src/interaction/interactionhandler.cpp @@ -953,7 +953,7 @@ void InteractionHandler::writeKeyboardDocumentation(const std::string& type, con if (type == "text") { std::ofstream f; f.exceptions(~std::ofstream::goodbit); - f.open(file); + f.open(absPath(file)); for (const auto& p : _keyLua) { f << std::to_string(p.first) << ": " << From 1778a7cdb6190c231b07181cb6631b7815ee863c Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 15 Sep 2016 13:28:52 +0200 Subject: [PATCH 63/92] Add documentation to SceneGraphNode --- include/openspace/scene/scenegraphnode.h | 4 + src/CMakeLists.txt | 1 + src/scene/scene_doc.inl | 5 +- src/scene/scenegraphnode.cpp | 19 ++- src/scene/scenegraphnode_doc.inl | 145 +++++++++++++++++++++++ 5 files changed, 170 insertions(+), 4 deletions(-) create mode 100644 src/scene/scenegraphnode_doc.inl diff --git a/include/openspace/scene/scenegraphnode.h b/include/openspace/scene/scenegraphnode.h index 4979eedcf8..1a08eeb54a 100644 --- a/include/openspace/scene/scenegraphnode.h +++ b/include/openspace/scene/scenegraphnode.h @@ -26,6 +26,8 @@ #define __SCENEGRAPHNODE_H__ // open space includes +#include + #include #include #include @@ -106,6 +108,8 @@ public: _ephemeris = eph; } + static Documentation Documentation(); + private: bool sphereInsideFrustum(const psc& s_pos, const PowerScaledScalar& s_rad, const Camera* camera); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c81f3999cc..6c87e7cd57 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -85,6 +85,7 @@ set(OPENSPACE_SOURCE ${OPENSPACE_BASE_DIR}/src/scene/scene_lua.inl ${OPENSPACE_BASE_DIR}/src/scene/scenegraph.cpp ${OPENSPACE_BASE_DIR}/src/scene/scenegraphnode.cpp + ${OPENSPACE_BASE_DIR}/src/scene/scenegraphnode_doc.inl ${OPENSPACE_BASE_DIR}/src/scripting/lualibrary.cpp ${OPENSPACE_BASE_DIR}/src/scripting/scriptengine.cpp ${OPENSPACE_BASE_DIR}/src/scripting/scriptengine_lua.inl diff --git a/src/scene/scene_doc.inl b/src/scene/scene_doc.inl index abd9c145e8..9b069572c1 100644 --- a/src/scene/scene_doc.inl +++ b/src/scene/scene_doc.inl @@ -29,7 +29,7 @@ namespace openspace { Documentation Scene::Documentation() { using namespace documentation; - return{ + return { "Scene Description", { { @@ -85,7 +85,8 @@ Documentation Scene::Documentation() { }), "This is the list of modules that will be loaded into the initial scene. The " "values in this table have to correspond to folders relative to the " - "ScenePath key." + "ScenePath key. The order in which the modules are loaded is the same as the " + "order in which they are specified in this table." } } }; diff --git a/src/scene/scenegraphnode.cpp b/src/scene/scenegraphnode.cpp index 3ac738de27..bf00e499ad 100644 --- a/src/scene/scenegraphnode.cpp +++ b/src/scene/scenegraphnode.cpp @@ -24,6 +24,9 @@ // open space includes #include + +#include + #include #include #include @@ -46,6 +49,8 @@ #include #include +#include "scenegraphnode_doc.inl" + namespace { const std::string _loggerCat = "SceneGraphNode"; const std::string KeyRenderable = "Renderable"; @@ -63,8 +68,18 @@ const std::string SceneGraphNode::KeyName = "Name"; const std::string SceneGraphNode::KeyParentName = "Parent"; const std::string SceneGraphNode::KeyDependencies = "Dependencies"; -SceneGraphNode* SceneGraphNode::createFromDictionary(const ghoul::Dictionary& dictionary) -{ +SceneGraphNode* SceneGraphNode::createFromDictionary(const ghoul::Dictionary& dictionary){ + // Perform testing against the documentation/specification + using namespace openspace::documentation; + TestResult testResult = testSpecification( + SceneGraphNode::Documentation(), + dictionary + ); + if (!testResult.success) { + throw SpecificationError(testResult, "SceneGraphNode"); + } + + SceneGraphNode* result = new SceneGraphNode; if (!dictionary.hasValue(KeyName)) { diff --git a/src/scene/scenegraphnode_doc.inl b/src/scene/scenegraphnode_doc.inl new file mode 100644 index 0000000000..b10c8e6468 --- /dev/null +++ b/src/scene/scenegraphnode_doc.inl @@ -0,0 +1,145 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +namespace openspace { + +Documentation SceneGraphNode::Documentation() { + using namespace documentation; + + return { + "Scenegraph Node", + { + { + "Name", + new StringVerifier, + "The name of this scenegraph node. This name must be unique among all scene " + "graph nodes that are loaded in a specific scene. If a duplicate is detected " + "the loading of the node will fail, as will all childing that depend on the " + "node." + }, + { + "Parent", + new StringAnnotationVerifier( + "Must be a name for another scenegraph node, or 'Root'" + ), + "This names the parent of the currently specified scenegraph node. The " + "parent must not have been defined earlier, but must exist at loading time, " + "or the scenegraph node creation will fail. A special parent 'Root' is " + "available that denotes the root of the scenegraph." + }, + { + "Renderable", + new TableVerifier({ + { + "Type", + new StringAnnotationVerifier( + "Must name a valid Renderable type." + ), + "The type of the specific renderable. The list of available " + "renderables depends on the configuration of the application and can " + "be written to disk at startup." + } + }), + "The renderable that is to be created for this scenegraph node. A renderable " + "is a component of a scenegraph node that will lead to some visual result on " + "the screen. The specifics heavily depend on the 'Type' of the renderable. " + "If no Renderable is specified, this scenegraph node is an internal node and " + "can be used for either group children, or apply common transformations to a " + "group of children.", + Optional::Yes + }, + { + "Transform", + new TableVerifier({ + { + "Translation", + new TableVerifier({ + { + "Type", + new StringAnnotationVerifier( + "Must name a valid Translation type." + ), + "The type of translation that is described in this element. " + "The available types of translations depend on the " + "configuration of the application and can be written to disk " + "on application startup." + } + }), + "This node describes a translation that is applied to the scenegraph " + "node and all its children. Depending on the 'Type' of the " + "translation, this can either be a static translation or a " + "time-varying one.", + Optional::Yes + }, + { + "Rotation", + new TableVerifier({ + { + "Type", + new StringAnnotationVerifier( + "Must name a valid Rotation type." + ), + "The type of the rotation that is described in this element. " + "The available types of rotations depend on the " + "configuration of the application and can be written to disk " + "on application startup." + } + }), + "This nodes describes a rotation that is applied to the scenegraph " + "node and all its children. Depending on the 'Type' of the rotation, " + "this can either be a static rotation or a time-varying one.", + Optional::Yes + }, + { + "Scale", + new TableVerifier({ + { + "Type", + new StringAnnotationVerifier( + "Must name a valid Scale type." + ), + "The type of the scaling that is described in this element. " + "The available types of scaling depend on the configuration " + "of the application and can be written to disk on " + "application startup." + } + }), + "This node describes a scaling that is applied to the scenegraph " + "node and all its children. Depending on the 'Type' of the scaling, " + "this can either be a static scaling or a time-varying one.", + Optional::Yes + } + }), + "This describes a set of transformations that are applied to this scenegraph " + "node and all of its children. There are only three possible values " + "corresponding to a 'Translation', a 'Rotation', and a 'Scale'.", + Optional::Yes + }, + } + }; +} + +} // namespace openspace From 43db84f62077d78a9850f2546846bfee359177b4 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 15 Sep 2016 13:40:39 +0200 Subject: [PATCH 64/92] Add method to automatically test a dictionary and throw on error --- .../openspace/documentation/documentation.h | 2 ++ src/documentation/documentation.cpp | 32 +++++++++++++------ src/engine/configurationmanager.cpp | 9 ++---- src/scene/scene.cpp | 9 ++---- src/scene/scenegraphnode.cpp | 11 ++----- 5 files changed, 33 insertions(+), 30 deletions(-) diff --git a/include/openspace/documentation/documentation.h b/include/openspace/documentation/documentation.h index 3f1074adcb..2d18c37249 100644 --- a/include/openspace/documentation/documentation.h +++ b/include/openspace/documentation/documentation.h @@ -73,6 +73,8 @@ struct Documentation { TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& dictionary); +void testSpecificationAndThrow(const Documentation& doc, + const ghoul::Dictionary& dictionary, std::string component); std::string generateDocumentation(const Documentation& d); diff --git a/src/documentation/documentation.cpp b/src/documentation/documentation.cpp index 71b026b66e..7c1a917adf 100644 --- a/src/documentation/documentation.cpp +++ b/src/documentation/documentation.cpp @@ -42,8 +42,7 @@ namespace documentation { SpecificationError::SpecificationError(TestResult result, std::string component) : ghoul::RuntimeError("Error in specification", std::move(component)) - , result(std::move(result)) -{} + , result(std::move(result)) {} DocumentationEntry::DocumentationEntry(std::string key, Verifier* t, std::string doc, @@ -51,19 +50,16 @@ DocumentationEntry::DocumentationEntry(std::string key, Verifier* t, std::string : key(std::move(key)) , tester(std::move(t)) , documentation(std::move(doc)) - , optional(optional) -{} + , optional(optional) {} Documentation::Documentation(std::string name, DocumentationEntries entries) : name(std::move(name)) - , entries(std::move(entries)) -{} + , entries(std::move(entries)) {} Documentation::Documentation(DocumentationEntries entries) - : Documentation("", std::move(entries)) -{} + : Documentation("", std::move(entries)) {} -TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& dictionary){ +TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& dictionary) { TestResult result; result.success = true; @@ -108,11 +104,27 @@ TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& di ); result.offenders = std::vector( uniqueOffenders.begin(), uniqueOffenders.end() - ); + ); return result; } +void testSpecificationAndThrow(const Documentation& doc, + const ghoul::Dictionary& dictionary, std::string component) + +{ + // Perform testing against the documentation/specification + using namespace openspace::documentation; + TestResult testResult = testSpecification( + doc, + dictionary + ); + if (!testResult.success) { + throw SpecificationError(std::move(testResult), std::move(component)); + } +} + + std::string generateDocumentation(const Documentation& d) { using namespace std::string_literals; std::string result; diff --git a/src/engine/configurationmanager.cpp b/src/engine/configurationmanager.cpp index f903f36f25..c0bfb1fc1d 100644 --- a/src/engine/configurationmanager.cpp +++ b/src/engine/configurationmanager.cpp @@ -113,14 +113,11 @@ void ConfigurationManager::loadFromFile(const string& filename) { ghoul::lua::loadDictionaryFromFile(filename, *this); // Perform testing against the documentation/specification - using namespace openspace::documentation; - TestResult result = testSpecification( + openspace::documentation::testSpecificationAndThrow( ConfigurationManager::Documentation(), - *this + *this, + "ConfigurationManager" ); - if (!result.success) { - throw SpecificationError(result, "ConfigurationManager"); - } // Register all the paths ghoul::Dictionary dictionary = value(KeyPaths); diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp index 7181a1d49d..c10b2ca2dd 100644 --- a/src/scene/scene.cpp +++ b/src/scene/scene.cpp @@ -190,14 +190,11 @@ bool Scene::loadSceneInternal(const std::string& sceneDescriptionFilePath) { ); // Perform testing against the documentation/specification - using namespace openspace::documentation; - TestResult result = testSpecification( + openspace::documentation::testSpecificationAndThrow( Scene::Documentation(), - dictionary + dictionary, + "Scene" ); - if (!result.success) { - throw SpecificationError(result, "Scene"); - } _graph.loadFromFile(sceneDescriptionFilePath); diff --git a/src/scene/scenegraphnode.cpp b/src/scene/scenegraphnode.cpp index bf00e499ad..e3334e178d 100644 --- a/src/scene/scenegraphnode.cpp +++ b/src/scene/scenegraphnode.cpp @@ -69,16 +69,11 @@ const std::string SceneGraphNode::KeyParentName = "Parent"; const std::string SceneGraphNode::KeyDependencies = "Dependencies"; SceneGraphNode* SceneGraphNode::createFromDictionary(const ghoul::Dictionary& dictionary){ - // Perform testing against the documentation/specification - using namespace openspace::documentation; - TestResult testResult = testSpecification( + openspace::documentation::testSpecificationAndThrow( SceneGraphNode::Documentation(), - dictionary + dictionary, + "SceneGraphNode" ); - if (!testResult.success) { - throw SpecificationError(testResult, "SceneGraphNode"); - } - SceneGraphNode* result = new SceneGraphNode; From 746a76e436dc6e6c8d012da57dc5fdfbc98fef4c Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 15 Sep 2016 13:47:52 +0200 Subject: [PATCH 65/92] Adding documentation to StaticScale --- modules/base/scale/staticscale.cpp | 27 ++++++++++++++++++--------- modules/base/scale/staticscale.h | 14 ++++++++------ 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/modules/base/scale/staticscale.cpp b/modules/base/scale/staticscale.cpp index ed9fddd71c..426a4c7e91 100644 --- a/modules/base/scale/staticscale.cpp +++ b/modules/base/scale/staticscale.cpp @@ -24,27 +24,36 @@ #include +#include + namespace { const std::string KeyValue = "Scale"; } namespace openspace { +Documentation StaticScale::Documentation() { + using namespace openspace::documentation; + return { + "Static Scaling", + {{ + KeyValue, + new DoubleVerifier, + "The scaling factor by which the scenegraph node is scaled." + }} + }; +} + StaticScale::StaticScale(const ghoul::Dictionary& dictionary) : _scaleValue(1.0) { - bool hasValue = dictionary.hasKeyAndValue(KeyValue); - if (hasValue) { - _scaleValue = dictionary.value(KeyValue); - } -} + documentation::testSpecificationAndThrow(Documentation(), dictionary, "StaticScale"); -StaticScale::~StaticScale() {} + _scaleValue = dictionary.value(KeyValue); +} double StaticScale::scaleValue() const { return _scaleValue; } -void StaticScale::update(const UpdateData&) {} - -} // namespace openspace \ No newline at end of file +} // namespace openspace diff --git a/modules/base/scale/staticscale.h b/modules/base/scale/staticscale.h index 68f2d65c1b..67388d3147 100644 --- a/modules/base/scale/staticscale.h +++ b/modules/base/scale/staticscale.h @@ -27,15 +27,17 @@ #include +#include + namespace openspace { -class StaticScale: public Scale { +class StaticScale : public Scale { public: - StaticScale(const ghoul::Dictionary& dictionary - = ghoul::Dictionary()); - virtual ~StaticScale(); - virtual double scaleValue() const; - virtual void update(const UpdateData& data) override; + StaticScale(const ghoul::Dictionary& dictionary = ghoul::Dictionary()); + double scaleValue() const; + + static Documentation Documentation(); + private: double _scaleValue; }; From a354f13ef3cb054c6a4bb29b2b6dccea1df9296f Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 15 Sep 2016 13:48:28 +0200 Subject: [PATCH 66/92] Adding DocumentationEngine --- .../openspace/documentation/documentationengine.h | 3 +++ include/openspace/engine/openspaceengine.h | 3 +++ include/openspace/util/openspacemodule.h | 4 ++++ modules/base/basemodule.cpp | 6 ++++++ modules/base/basemodule.h | 2 ++ src/documentation/documentationengine.cpp | 6 ++++++ src/engine/openspaceengine.cpp | 13 +++++++++++++ src/rendering/renderengine.cpp | 6 ++++-- src/util/openspacemodule.cpp | 4 ++++ 9 files changed, 45 insertions(+), 2 deletions(-) diff --git a/include/openspace/documentation/documentationengine.h b/include/openspace/documentation/documentationengine.h index 82f2ef33b8..84ef2275f7 100644 --- a/include/openspace/documentation/documentationengine.h +++ b/include/openspace/documentation/documentationengine.h @@ -33,8 +33,11 @@ namespace documentation { class DocumentationEngine { public: + void addDocumentation(Documentation doc); private: + std::vector _documentations; + }; } // namespace documentation diff --git a/include/openspace/engine/openspaceengine.h b/include/openspace/engine/openspaceengine.h index 99b6507d78..1ea655b46d 100644 --- a/include/openspace/engine/openspaceengine.h +++ b/include/openspace/engine/openspaceengine.h @@ -55,6 +55,7 @@ class ModuleEngine; class WindowWrapper; class SettingsEngine; +namespace documentation { class DocumentationEngine; } namespace interaction { class InteractionHandler; } namespace gui { class GUI; } //namespace scripting { class ScriptEngine; } @@ -77,6 +78,7 @@ public: // Guaranteed to return a valid pointer ConfigurationManager& configurationManager(); + documentation::DocumentationEngine& documentationEngine(); interaction::InteractionHandler& interactionHandler(); RenderEngine& renderEngine(); scripting::ScriptEngine& scriptEngine(); @@ -135,6 +137,7 @@ private: // Components std::unique_ptr _configurationManager; + std::unique_ptr _documentationEngine; std::unique_ptr _interactionHandler; std::unique_ptr _renderEngine; std::unique_ptr _scriptEngine; diff --git a/include/openspace/util/openspacemodule.h b/include/openspace/util/openspacemodule.h index 350c853f65..2cda76686a 100644 --- a/include/openspace/util/openspacemodule.h +++ b/include/openspace/util/openspacemodule.h @@ -27,6 +27,8 @@ #include +#include + #include #include @@ -64,6 +66,8 @@ public: */ void deinitialize(); + virtual std::vector documentations() const; + protected: /** * Customization point for each derived class. The internalInitialize method is called diff --git a/modules/base/basemodule.cpp b/modules/base/basemodule.cpp index 196913f848..fb5731ec9f 100644 --- a/modules/base/basemodule.cpp +++ b/modules/base/basemodule.cpp @@ -119,4 +119,10 @@ void BaseModule::internalInitialize() { fModelGeometry->registerClass("MultiModelGeometry"); } +std::vector BaseModule::documentations() const { + return { + StaticScale::Documentation() + }; +} + } // namespace openspace diff --git a/modules/base/basemodule.h b/modules/base/basemodule.h index ffad43acf1..f9838dbe31 100644 --- a/modules/base/basemodule.h +++ b/modules/base/basemodule.h @@ -33,6 +33,8 @@ class BaseModule : public OpenSpaceModule { public: BaseModule(); + std::vector documentations() const override; + protected: void internalInitialize() override; }; diff --git a/src/documentation/documentationengine.cpp b/src/documentation/documentationengine.cpp index efc4309bae..455242b7f1 100644 --- a/src/documentation/documentationengine.cpp +++ b/src/documentation/documentationengine.cpp @@ -24,10 +24,16 @@ #include +#include + namespace openspace { namespace documentation { +void DocumentationEngine::addDocumentation(Documentation doc) { + _documentations.push_back(std::move(doc)); +} + } // namespace documentation } // namespace openspace diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index c6c58c861e..0904fc12ef 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -26,6 +26,7 @@ #include +#include #include #include #include @@ -120,6 +121,7 @@ OpenSpaceEngine* OpenSpaceEngine::_engine = nullptr; OpenSpaceEngine::OpenSpaceEngine(std::string programName, std::unique_ptr windowWrapper) : _configurationManager(new ConfigurationManager) + , _documentationEngine(new documentation::DocumentationEngine) , _interactionHandler(new interaction::InteractionHandler) , _renderEngine(new RenderEngine) , _scriptEngine(new scripting::ScriptEngine) @@ -147,6 +149,7 @@ OpenSpaceEngine::OpenSpaceEngine(std::string programName, _interactionHandler->setPropertyOwner(_globalPropertyNamespace.get()); _globalPropertyNamespace->addPropertySubOwner(_interactionHandler.get()); _globalPropertyNamespace->addPropertySubOwner(_settingsEngine.get()); + FactoryManager::initialize(); FactoryManager::ref().addFactory( std::make_unique>() @@ -158,6 +161,8 @@ OpenSpaceEngine::OpenSpaceEngine(std::string programName, Time::initialize(); ghoul::systemcapabilities::SystemCapabilities::initialize(); TransformationManager::initialize(); + + _documentationEngine->addDocumentation(ConfigurationManager::Documentation()); } OpenSpaceEngine::~OpenSpaceEngine() { @@ -292,6 +297,14 @@ bool OpenSpaceEngine::create(int argc, char** argv, // Register modules _engine->_moduleEngine->initialize(); + // After registering the modules, the documentations for the available classes + // can be added as well + for (OpenSpaceModule* m : _engine->_moduleEngine->modules()) { + for (auto&& doc : m->documentations()) { + _engine->_documentationEngine->addDocumentation(doc); + } + } + // Create the cachemanager FileSys.createCacheManager( absPath("${" + ConfigurationManager::KeyCache + "}"), CacheVersion diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index 26f4f2efa7..61752e8a93 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -40,6 +40,7 @@ #include +#include #include #include #include @@ -136,6 +137,8 @@ RenderEngine::RenderEngine() 12, -1 }; + + OsEng.documentationEngine().addDocumentation(Scene::Documentation()); } RenderEngine::~RenderEngine() { @@ -493,8 +496,7 @@ void RenderEngine::toggleFrametimeType(int t) { } Scene* RenderEngine::scene() { - // TODO custom assert (ticket #5) - assert(_sceneGraph); + ghoul_assert(_sceneGraph, "Scenegraph not initialized"); return _sceneGraph; } diff --git a/src/util/openspacemodule.cpp b/src/util/openspacemodule.cpp index 3c71ffaf67..dc61f1c014 100644 --- a/src/util/openspacemodule.cpp +++ b/src/util/openspacemodule.cpp @@ -63,6 +63,10 @@ void OpenSpaceModule::deinitialize() { internalDeinitialize(); } +std::vector OpenSpaceModule::documentations() const { + return {}; +} + std::string OpenSpaceModule::modulePath() const { std::string moduleName = name(); std::transform(moduleName.begin(), moduleName.end(), moduleName.begin(), tolower); From 408280a53332490c795219c36cfda5f5d55953f0 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 15 Sep 2016 15:35:23 +0200 Subject: [PATCH 67/92] Rearrange and rename constants in ConfigurationManager Make use of constants in ConfigurationManager documentation --- .../openspace/engine/configurationmanager.h | 45 ++++++---- openspace.cfg | 12 ++- src/engine/configurationmanager.cpp | 34 +++++--- src/engine/configurationmanager_doc.inl | 87 +++++++++++++------ src/engine/logfactory.cpp | 2 +- src/engine/openspaceengine.cpp | 41 ++++++--- src/scene/scene.cpp | 30 +++++-- src/scripting/scriptengine.cpp | 17 ++-- 8 files changed, 179 insertions(+), 89 deletions(-) diff --git a/include/openspace/engine/configurationmanager.h b/include/openspace/engine/configurationmanager.h index bb105eab2b..be33b3fafd 100644 --- a/include/openspace/engine/configurationmanager.h +++ b/include/openspace/engine/configurationmanager.h @@ -51,22 +51,20 @@ public: /// The key that stores the location of the SGCT configuration file that is used on /// application launch static const std::string KeyConfigSgct; - /// The key that stores the type of Lua documentation that should be stored - static const std::string KeyLuaDocumentationType; - /// The key that stores the save location of the Lua documentation - static const std::string KeyLuaDocumentationFile; - /// The key that stores the type of scripting log that should be stored - static const std::string KeyScriptLogType; - /// The key that stores the save location of the scripting log - static const std::string KeyScriptLogFile; - /// The key that stores the type of Property documentation that should be stored - static const std::string KeyPropertyDocumentationType; - /// The key that stores the save location of the Property documentation - static const std::string KeyPropertyDocumentationFile; - /// The key that stores the type of keyboard bindings that should be stored - static const std::string KeyKeyboardShortcutsType; - /// The key that stores the save location of the keyboard bindings file - static const std::string KeyKeyboardShortcutsFile; + /// The part of the key that defines the type + static const std::string PartType; + /// The part of the key that defines the file + static const std::string PartFile; + /// The key that stores the Lua documentation + static const std::string KeyLuaDocumentation; + /// The key that stores the scripting log + static const std::string KeyScriptLog; + /// The key that stores the Property documentation + static const std::string KeyPropertyDocumentation; + /// The key that stores the keyboard bindings that should be stored + static const std::string KeyKeyboardShortcuts; + /// The key that stores the main documentation + static const std::string KeyDocumentation; /// The key that stores the location of the scene file that is initially loaded static const std::string KeyConfigScene; /// The key that stores the subdirectory containing a list of all startup scripts to @@ -75,18 +73,24 @@ public: /// The key that stores the subdirectory containing a list of all settings scripts to /// be executed on application start and after the scene file is loaded static const std::string KeySettingsScript; + /// The key that stores the settings for determining log-related settings + static const std::string KeyLogging; /// The key that stores the desired LogLevel for the whole application /// \sa ghoul::logging::LogManager - static const std::string KeyLogLevel; + static const std::string PartLogLevel; /// The key that stores whether the log should be immediately flushed after a n /// \sa ghoul::logging::LogManager - static const std::string KeyLogImmediateFlush; + static const std::string PartImmediateFlush; /// The key that stores a subdirectory with a description for additional /// ghoul::logging::Log%s to be created /// \sa LogFactory - static const std::string KeyLogs; + static const std::string PartLogs; + /// The key that stores whether a log should be appended to or should be overwritten + static const std::string PartAppend; /// The key that stores the verbosity (None, Minimal, Default, Full) of the system /// capabilities components + static const std::string PartCapabilitiesVerbosity; + /// The full key that stores the verbosity of the system capabilities component static const std::string KeyCapabilitiesVerbosity; /// The key that stores the time (in seconds) that the application will wait before /// shutting down after the shutdown call is made @@ -97,6 +101,9 @@ public: /// The key that sets the request URL that is used to request additional data to be /// downloaded static const std::string KeyDownloadRequestURL; + /// The key that stores the switch for enabling/disabling the rendering on a master + /// computer + static const std::string KeyRenderingMethod; /** * Iteratively walks the directory structure starting with \p filename to find the diff --git a/openspace.cfg b/openspace.cfg index 0e1f8a6d9a..df4f338ec5 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -36,19 +36,19 @@ return { LogLevel = "Debug", ImmediateFlush = true, Logs = { - { Type = "html", FileName = "${BASE_PATH}/log.html", Append = false } + { Type = "html", File = "${BASE_PATH}/log.html", Append = false } }, CapabilitiesVerbosity = "Full" }, - LuaDocumentationFile = { + LuaDocumentation = { Type = "text", File = "${BASE_PATH}/LuaScripting.txt" }, - PropertyDocumentationFile = { + PropertyDocumentation = { Type = "text", File = "${BASE_PATH}/Properties.txt" }, - ScriptLogFile = { + ScriptLog = { Type = "text", File = "${BASE_PATH}/ScriptLog.txt" }, @@ -56,6 +56,10 @@ return { Type = "text", File = "${BASE_PATH}/KeyboardMapping.txt" }, + Documentation = { + Type = "text", + File = "${BASE_PATH}/Documentation.txt" + }, ShutdownCountdown = 3, DownloadRequestURL = "http://130.236.132.168/request.cgi", RenderingMethod = "Framebuffer" diff --git a/src/engine/configurationmanager.cpp b/src/engine/configurationmanager.cpp index c0bfb1fc1d..5f737a39db 100644 --- a/src/engine/configurationmanager.cpp +++ b/src/engine/configurationmanager.cpp @@ -45,25 +45,31 @@ const string ConfigurationManager::KeyPaths = "Paths"; const string ConfigurationManager::KeyCache = "CACHE"; const string ConfigurationManager::KeyFonts = "Fonts"; const string ConfigurationManager::KeyConfigSgct = "SGCTConfig"; -const string ConfigurationManager::KeyLuaDocumentationType = "LuaDocumentationFile.Type"; -const string ConfigurationManager::KeyLuaDocumentationFile = "LuaDocumentationFile.File"; -const string ConfigurationManager::KeyScriptLogType = "ScriptLogFile.Type"; -const string ConfigurationManager::KeyScriptLogFile = "ScriptLogFile.File"; -const string ConfigurationManager::KeyPropertyDocumentationType = - "PropertyDocumentationFile.Type"; -const string ConfigurationManager::KeyPropertyDocumentationFile = - "PropertyDocumentationFile.File"; -const string ConfigurationManager::KeyKeyboardShortcutsType = "KeyboardShortcuts.Type"; -const string ConfigurationManager::KeyKeyboardShortcutsFile = "KeyboardShortcuts.File"; + +const string ConfigurationManager::PartType = "Type"; +const string ConfigurationManager::PartFile = "File"; + +const string ConfigurationManager::KeyLuaDocumentation = "LuaDocumentation"; +const string ConfigurationManager::KeyScriptLog = "ScriptLog"; +const string ConfigurationManager::KeyPropertyDocumentation = "PropertyDocumentation"; +const string ConfigurationManager::KeyKeyboardShortcuts = "KeyboardShortcuts"; +const string ConfigurationManager::KeyDocumentation = "Documentation"; const string ConfigurationManager::KeyConfigScene = "Scene"; -const string ConfigurationManager::KeyLogLevel = "Logging.LogLevel"; -const string ConfigurationManager::KeyLogImmediateFlush = "Logging.ImmediateFlush"; -const string ConfigurationManager::KeyLogs = "Logging.Logs"; + +const string ConfigurationManager::KeyLogging = "Logging"; +const string ConfigurationManager::PartLogLevel = "LogLevel"; +const string ConfigurationManager::PartImmediateFlush = "ImmediateFlush"; +const string ConfigurationManager::PartLogs = "Logs"; +const string ConfigurationManager::PartAppend = "Append"; +const string ConfigurationManager::PartCapabilitiesVerbosity = "CapabilitiesVerbosity"; + const string ConfigurationManager::KeyCapabilitiesVerbosity = - "Logging.CapabilitiesVerbosity"; + KeyLogging + "." + PartCapabilitiesVerbosity; + const string ConfigurationManager::KeyShutdownCountdown = "ShutdownCountdown"; const string ConfigurationManager::KeyDisableMasterRendering = "DisableRenderingOnMaster"; const string ConfigurationManager::KeyDownloadRequestURL = "DownloadRequestURL"; +const string ConfigurationManager::KeyRenderingMethod = "RenderingMethod"; string ConfigurationManager::findConfiguration(const string& filename) { using ghoul::filesystem::Directory; diff --git a/src/engine/configurationmanager_doc.inl b/src/engine/configurationmanager_doc.inl index 69977b3bee..7ec2264f54 100644 --- a/src/engine/configurationmanager_doc.inl +++ b/src/engine/configurationmanager_doc.inl @@ -33,13 +33,13 @@ Documentation ConfigurationManager::Documentation() { "OpenSpace Configuration", { { - "SGCTConfig", + ConfigurationManager::KeyConfigSgct, new StringAnnotationVerifier("A valid SGCT configuration file"), "The SGCT configuration file that determines the window and view frustum " "settings that are being used when OpenSpace is started." }, { - "Scene", + ConfigurationManager::KeyConfigScene, new StringAnnotationVerifier( "A valid scene file as described in the Scene documentation"), "The scene description that is used to populate the application after " @@ -48,7 +48,7 @@ Documentation ConfigurationManager::Documentation() { "the Scene documentation." }, { - "Paths", + ConfigurationManager::KeyPaths, new TableVerifier({ { "*", new StringVerifier } }), @@ -58,7 +58,7 @@ Documentation ConfigurationManager::Documentation() { Optional::Yes }, { - "Fonts", + ConfigurationManager::KeyFonts, new TableVerifier({ { "*", new StringVerifier, "Font paths loadable by FreeType" } }), @@ -68,10 +68,10 @@ Documentation ConfigurationManager::Documentation() { Optional::Yes }, { - "Logging", + ConfigurationManager::KeyLogging, new TableVerifier({ { - "LogLevel", + ConfigurationManager::PartLogLevel, new StringInListVerifier( // List from logmanager.cpp::levelFromString {"Debug", "Info", "Warning", "Error", "Fatal", "None" } @@ -83,7 +83,7 @@ Documentation ConfigurationManager::Documentation() { Optional::Yes }, { - "ImmediateFlush", + ConfigurationManager::PartImmediateFlush, new BoolVerifier, "Determines whether error messages will be displayed immediately " "or if it is acceptable to have a short delay, but being more " @@ -93,13 +93,13 @@ Documentation ConfigurationManager::Documentation() { Optional::Yes }, { - "Logs", + ConfigurationManager::PartLogs, new TableVerifier({ { "*", new TableVerifier({ { - "Type", + ConfigurationManager::PartType, new StringInListVerifier({ // List from logfactory.cpp::createLog "text", "html" @@ -107,12 +107,12 @@ Documentation ConfigurationManager::Documentation() { "The type of the new log to be generated." }, { - "FileName", + ConfigurationManager::PartFile, new StringVerifier, "The filename to which the log will be written." }, { - "Append", + ConfigurationManager::PartAppend, new BoolVerifier, "Determines whether the file will be cleared at " "startup or if the contents will be appended to " @@ -131,7 +131,7 @@ Documentation ConfigurationManager::Documentation() { Optional::Yes }, { - "CapabilitiesVerbosity", + ConfigurationManager::PartCapabilitiesVerbosity, new StringInListVerifier( // List from OpenspaceEngine::initialize { "None", "Minimal", "Default", "Full" } @@ -147,10 +147,10 @@ Documentation ConfigurationManager::Documentation() { Optional::Yes }, { - "LuaDocumentationFile", + ConfigurationManager::KeyLuaDocumentation, new TableVerifier({ { - "Type", + ConfigurationManager::PartType, new StringInListVerifier( // List from ScriptEngine::writeDocumentation { "text", "html" } @@ -158,7 +158,7 @@ Documentation ConfigurationManager::Documentation() { "The type of documentation that will be written." }, { - "File", + ConfigurationManager::PartFile, new StringVerifier, "The filename that will be created on startup containing the " "documentation of available Lua functions. Any existing file " @@ -171,10 +171,10 @@ Documentation ConfigurationManager::Documentation() { Optional::Yes }, { - "PropertyDocumentationFile", + ConfigurationManager::KeyPropertyDocumentation, new TableVerifier({ { - "Type", + ConfigurationManager::PartType, new StringInListVerifier( // List taken from Scene::writePropertyDocumentation { "text", "html" } @@ -182,7 +182,7 @@ Documentation ConfigurationManager::Documentation() { "The type of property documentation file that is created." }, { - "File", + ConfigurationManager::PartFile, new StringVerifier, "The file that will be created on startup containing a list of " "all properties in the scene. Any existing file will be silently " @@ -194,10 +194,10 @@ Documentation ConfigurationManager::Documentation() { Optional::Yes }, { - "ScriptLogFile", + ConfigurationManager::KeyScriptLog, new TableVerifier({ { - "Type", + ConfigurationManager::PartType, new StringInListVerifier( // List taken from ScriptEngine::writeLog { "text" } @@ -205,7 +205,7 @@ Documentation ConfigurationManager::Documentation() { "The type of logfile that will be created." }, { - "File", + ConfigurationManager::PartFile, new StringVerifier, "The file that will be created on startup containing the log of " "all Lua scripts that are executed. Any existing file (including " @@ -217,10 +217,10 @@ Documentation ConfigurationManager::Documentation() { Optional::Yes }, { - "KeyboardShortcuts", + ConfigurationManager::KeyKeyboardShortcuts, new TableVerifier({ { - "Type", + ConfigurationManager::PartType, new StringInListVerifier( // List from InteractionHandler::writeKeyboardDocumentation { "text", "html" } @@ -229,10 +229,11 @@ Documentation ConfigurationManager::Documentation() { "written." }, { - "File", + ConfigurationManager::PartFile, new StringVerifier, "The file that will be created on startup containing the list of " - "all keyboard bindings with their respective Lua scripts." + "all keyboard bindings with their respective Lua scripts. Any " + "previous file in this location will be silently overritten." } }), "Contains the collection of all keyboard shortcuts that were collected " @@ -241,7 +242,29 @@ Documentation ConfigurationManager::Documentation() { Optional::Yes }, { - "ShutdownCountdown", + ConfigurationManager::KeyDocumentation, + new TableVerifier({ + { + ConfigurationManager::PartType, + new StringInListVerifier( + // List from DocumentationEngine::writeDocumentation + { "text", "html" } + ), + "The type of documentation that should be written." + }, + { + ConfigurationManager::PartFile, + new StringVerifier, + "The file that will be created on startup containing this " + "documentation. Any previous file in this location will be silently " + "overritten." + } + }), + "This defines the location and type of this documentation file.", + Optional::Yes + }, + { + ConfigurationManager::KeyShutdownCountdown, new DoubleGreaterEqualVerifier(0.0), "The countdown that the application will wait between pressing ESC and " "actually shutting down. If ESC is pressed again in this time, the " @@ -249,7 +272,7 @@ Documentation ConfigurationManager::Documentation() { Optional::Yes }, { - "DownloadRequestURL", + ConfigurationManager::KeyDownloadRequestURL, new OrVerifier( new StringVerifier, new TableVerifier({ @@ -262,7 +285,7 @@ Documentation ConfigurationManager::Documentation() { Optional::Yes }, { - "RenderingMethod", + ConfigurationManager::KeyRenderingMethod, new StringInListVerifier( // List from RenderEngine::setRendererFromString { "Framebuffer", "ABuffer" } @@ -270,6 +293,14 @@ Documentation ConfigurationManager::Documentation() { "The renderer that is use after startup. The renderer 'ABuffer' requires " "support for at least OpenGL 4.3", Optional::Yes + }, + { + ConfigurationManager::KeyDisableMasterRendering, + new BoolVerifier, + "Toggles whether the master in a multi-application setup should be rendering " + "or just managing the state of the network. This is desired in cases where " + "the master computer does not have the resources to render a scene.", + Optional::Yes } } }; diff --git a/src/engine/logfactory.cpp b/src/engine/logfactory.cpp index 21a83f7c87..ffc145d95e 100644 --- a/src/engine/logfactory.cpp +++ b/src/engine/logfactory.cpp @@ -32,7 +32,7 @@ namespace { const std::string keyType = "Type"; - const std::string keyFilename = "FileName"; + const std::string keyFilename = "File"; const std::string keyAppend = "Append"; const std::string keyTimeStamping = "TimeStamping"; const std::string keyDateStamping = "DateStamping"; diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 0904fc12ef..9bfd2a0bb4 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -367,7 +367,9 @@ bool OpenSpaceEngine::initialize() { using Verbosity = ghoul::systemcapabilities::SystemCapabilitiesComponent::Verbosity; Verbosity verbosity = Verbosity::Default; - if (configurationManager().hasKeyAndValue(ConfigurationManager::KeyCapabilitiesVerbosity)) { + if (configurationManager().hasKeyAndValue( + + ConfigurationManager::KeyCapabilitiesVerbosity)) { std::map verbosityMap = { { "None", Verbosity::None }, { "Minimal", Verbosity::Minimal }, @@ -408,13 +410,18 @@ bool OpenSpaceEngine::initialize() { scriptEngine().initialize(); // If a LuaDocumentationFile was specified, generate it now - const bool hasType = configurationManager().hasKey(ConfigurationManager::KeyLuaDocumentationType); - const bool hasFile = configurationManager().hasKey(ConfigurationManager::KeyLuaDocumentationFile); + const std::string LuaDocumentationType = + ConfigurationManager::KeyLuaDocumentation + "." + ConfigurationManager::PartType; + const std::string LuaDocumentationFile = + ConfigurationManager::KeyLuaDocumentation + "." + ConfigurationManager::PartFile; + + const bool hasType = configurationManager().hasKey(LuaDocumentationType); + const bool hasFile = configurationManager().hasKey(LuaDocumentationFile); if (hasType && hasFile) { std::string luaDocumentationType; - configurationManager().getValue(ConfigurationManager::KeyLuaDocumentationType, luaDocumentationType); + configurationManager().getValue(LuaDocumentationType, luaDocumentationType); std::string luaDocumentationFile; - configurationManager().getValue(ConfigurationManager::KeyLuaDocumentationFile, luaDocumentationFile); + configurationManager().getValue(LuaDocumentationFile, luaDocumentationFile); luaDocumentationFile = absPath(luaDocumentationFile); _scriptEngine->writeDocumentation(luaDocumentationFile, luaDocumentationType); @@ -680,12 +687,21 @@ void OpenSpaceEngine::loadFonts() { } void OpenSpaceEngine::configureLogging() { - if (configurationManager().hasKeyAndValue(ConfigurationManager::KeyLogLevel)) { + const std::string KeyLogLevel = + ConfigurationManager::KeyLogging + '.' + ConfigurationManager::PartLogLevel; + const std::string KeyLogImmediateFlush = + ConfigurationManager::KeyLogging + '.' + ConfigurationManager::PartImmediateFlush; + const std::string KeyLogs = + ConfigurationManager::KeyLogging + '.' + ConfigurationManager::PartLogs; + + + + if (configurationManager().hasKeyAndValue(KeyLogLevel)) { std::string logLevel; - configurationManager().getValue(ConfigurationManager::KeyLogLevel, logLevel); + configurationManager().getValue(KeyLogLevel, logLevel); bool immediateFlush = false; - configurationManager().getValue(ConfigurationManager::KeyLogImmediateFlush, immediateFlush); + configurationManager().getValue(KeyLogImmediateFlush, immediateFlush); LogManager::LogLevel level = LogManager::levelFromString(logLevel); LogManager::deinitialize(); @@ -697,9 +713,9 @@ void OpenSpaceEngine::configureLogging() { LogMgr.addLog(std::make_unique()); } - if (configurationManager().hasKeyAndValue(ConfigurationManager::KeyLogs)) { + if (configurationManager().hasKeyAndValue(KeyLogs)) { ghoul::Dictionary logs; - configurationManager().getValue(ConfigurationManager::KeyLogs, logs); + configurationManager().getValue(KeyLogs, logs); for (size_t i = 1; i <= logs.size(); ++i) { ghoul::Dictionary logInfo; @@ -1002,6 +1018,11 @@ void OpenSpaceEngine::disableBarrier() { _windowWrapper->setBarrier(false); } +documentation::DocumentationEngine& OpenSpaceEngine::documentationEngine() { + ghoul_assert(_documentationEngine, "DocumentationEngine must not be nullptr"); + return *_documentationEngine; +} + NetworkEngine& OpenSpaceEngine::networkEngine() { ghoul_assert(_networkEngine, "NetworkEngine must not be nullptr"); return *_networkEngine; diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp index c10b2ca2dd..85e71717df 100644 --- a/src/scene/scene.cpp +++ b/src/scene/scene.cpp @@ -98,15 +98,23 @@ void Scene::update(const UpdateData& data) { OsEng.interactionHandler().setInteractionMode("Orbital"); // After loading the scene, the keyboard bindings have been set - + const std::string KeyboardShortcutsType = + ConfigurationManager::KeyKeyboardShortcuts + "." + + ConfigurationManager::PartType; + + const std::string KeyboardShortcutsFile = + ConfigurationManager::KeyKeyboardShortcuts + "." + + ConfigurationManager::PartFile; + + std::string type; std::string file; bool hasType = OsEng.configurationManager().getValue( - ConfigurationManager::KeyKeyboardShortcutsType, type + KeyboardShortcutsType, type ); bool hasFile = OsEng.configurationManager().getValue( - ConfigurationManager::KeyKeyboardShortcutsFile, file + KeyboardShortcutsFile, file ); if (hasType && hasFile) { @@ -238,13 +246,21 @@ bool Scene::loadSceneInternal(const std::string& sceneDescriptionFilePath) { } // If a PropertyDocumentationFile was specified, generate it now - const bool hasType = OsEng.configurationManager().hasKey(ConfigurationManager::KeyPropertyDocumentationType); - const bool hasFile = OsEng.configurationManager().hasKey(ConfigurationManager::KeyPropertyDocumentationFile); + const std::string KeyPropertyDocumentationType = + ConfigurationManager::KeyPropertyDocumentation + '.' + + ConfigurationManager::PartType; + + const std::string KeyPropertyDocumentationFile = + ConfigurationManager::KeyPropertyDocumentation + '.' + + ConfigurationManager::PartFile; + + const bool hasType = OsEng.configurationManager().hasKey(KeyPropertyDocumentationType); + const bool hasFile = OsEng.configurationManager().hasKey(KeyPropertyDocumentationFile); if (hasType && hasFile) { std::string propertyDocumentationType; - OsEng.configurationManager().getValue(ConfigurationManager::KeyPropertyDocumentationType, propertyDocumentationType); + OsEng.configurationManager().getValue(KeyPropertyDocumentationType, propertyDocumentationType); std::string propertyDocumentationFile; - OsEng.configurationManager().getValue(ConfigurationManager::KeyPropertyDocumentationFile, propertyDocumentationFile); + OsEng.configurationManager().getValue(KeyPropertyDocumentationFile, propertyDocumentationFile); propertyDocumentationFile = absPath(propertyDocumentationFile); writePropertyDocumentation(propertyDocumentationFile, propertyDocumentationType); diff --git a/src/scripting/scriptengine.cpp b/src/scripting/scriptengine.cpp index cd5b416082..5f396d68f9 100644 --- a/src/scripting/scriptengine.cpp +++ b/src/scripting/scriptengine.cpp @@ -597,18 +597,23 @@ void ScriptEngine::writeDocumentation(const std::string& filename, const std::st } bool ScriptEngine::writeLog(const std::string& script) { + const std::string KeyScriptLogType = + ConfigurationManager::KeyScriptLog + '.' + ConfigurationManager::PartType; + const std::string KeyScriptLogFile = + ConfigurationManager::KeyScriptLog + '.' + ConfigurationManager::PartFile; + // Check that logging is enabled and initialize if necessary if (!_logFileExists) { // If a ScriptLogFile was specified, generate it now const bool hasType = OsEng.configurationManager() - .hasKey(ConfigurationManager::KeyScriptLogType); + .hasKey(KeyScriptLogType); const bool hasFile = OsEng.configurationManager() - .hasKey(ConfigurationManager::KeyScriptLogFile); + .hasKey(KeyScriptLogFile); if (hasType && hasFile) { OsEng.configurationManager() - .getValue(ConfigurationManager::KeyScriptLogType, _logType); + .getValue(KeyScriptLogType, _logType); OsEng.configurationManager() - .getValue(ConfigurationManager::KeyScriptLogFile, _logFilename); + .getValue(KeyScriptLogFile, _logFilename); _logFilename = absPath(_logFilename); _logFileExists = true; @@ -627,8 +632,8 @@ bool ScriptEngine::writeLog(const std::string& script) { } } else { LDEBUG("No script log specified in 'openspace.cfg.' To log, set '" - << ConfigurationManager::KeyScriptLogType << " and " - << ConfigurationManager::KeyScriptLogFile + << KeyScriptLogType << " and " + << KeyScriptLogFile << " in configuration table."); _logScripts = false; return false; From 7e35cf5823a9873a0467e09a5bc441319390e6eb Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 15 Sep 2016 18:02:13 +0200 Subject: [PATCH 68/92] Make InteractionHandler not crash if the Camera focus node is not found --- src/interaction/interactionhandler.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/interaction/interactionhandler.cpp b/src/interaction/interactionhandler.cpp index 8f8d389c09..0c8d324daf 100644 --- a/src/interaction/interactionhandler.cpp +++ b/src/interaction/interactionhandler.cpp @@ -794,8 +794,10 @@ void InteractionHandler::postSynchronizationPreDraw() { _cameraUpdatedFromScript = false; } else { - _currentInteractionMode->updateCameraStateFromMouseStates(*_camera); - _camera->setFocusPositionVec3(focusNode()->worldPosition()); + if (_camera && focusNode()) { + _currentInteractionMode->updateCameraStateFromMouseStates(*_camera); + _camera->setFocusPositionVec3(focusNode()->worldPosition()); + } } } From 6a2eda393cd1d95836553f00d247ff8ab08616b5 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 15 Sep 2016 18:02:29 +0200 Subject: [PATCH 69/92] Make StaticScale be creatable without a Dictionary --- modules/base/scale/staticscale.cpp | 5 +++++ modules/base/scale/staticscale.h | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/modules/base/scale/staticscale.cpp b/modules/base/scale/staticscale.cpp index 426a4c7e91..2e01ecff43 100644 --- a/modules/base/scale/staticscale.cpp +++ b/modules/base/scale/staticscale.cpp @@ -44,6 +44,11 @@ Documentation StaticScale::Documentation() { }; } +StaticScale::StaticScale() + : _scaleValue(1.0) +{} + + StaticScale::StaticScale(const ghoul::Dictionary& dictionary) : _scaleValue(1.0) { diff --git a/modules/base/scale/staticscale.h b/modules/base/scale/staticscale.h index 67388d3147..5725f06a06 100644 --- a/modules/base/scale/staticscale.h +++ b/modules/base/scale/staticscale.h @@ -33,7 +33,8 @@ namespace openspace { class StaticScale : public Scale { public: - StaticScale(const ghoul::Dictionary& dictionary = ghoul::Dictionary()); + StaticScale(); + StaticScale(const ghoul::Dictionary& dictionary); double scaleValue() const; static Documentation Documentation(); From f22f01ce95d15eab06aac2581cdc0681197f6322 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 15 Sep 2016 18:02:56 +0200 Subject: [PATCH 70/92] More work on DocumentationEngine --- .gitignore | 1 + .../documentation/documentationengine.h | 2 ++ src/documentation/documentationengine.cpp | 12 ++++++++++ src/engine/openspaceengine.cpp | 24 ++++++++++++++++--- src/rendering/renderengine.cpp | 2 -- 5 files changed, 36 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index b6ff87250c..3b94161ec7 100644 --- a/.gitignore +++ b/.gitignore @@ -120,3 +120,4 @@ data/spice/Rosetta/ KeyboardMapping.html LuaScripting.html Properties.html +Documentation.txt diff --git a/include/openspace/documentation/documentationengine.h b/include/openspace/documentation/documentationengine.h index 84ef2275f7..ddc586b9c6 100644 --- a/include/openspace/documentation/documentationengine.h +++ b/include/openspace/documentation/documentationengine.h @@ -33,6 +33,8 @@ namespace documentation { class DocumentationEngine { public: + void writeDocumentation(const std::string& filename, const std::string& type); + void addDocumentation(Documentation doc); private: diff --git a/src/documentation/documentationengine.cpp b/src/documentation/documentationengine.cpp index 455242b7f1..d3067f4179 100644 --- a/src/documentation/documentationengine.cpp +++ b/src/documentation/documentationengine.cpp @@ -26,10 +26,22 @@ #include +#include + namespace openspace { namespace documentation { +void DocumentationEngine::writeDocumentation(const std::string& f, const std::string& t) { + if (t == "text") { + std::ofstream file; + file.exceptions(~std::ofstream::goodbit); + file.open(f); + for (const Documentation& d : _documentations) { + file << documentation::generateDocumentation(d) << std::endl << std::endl; + } + } +} void DocumentationEngine::addDocumentation(Documentation doc) { _documentations.push_back(std::move(doc)); diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 9bfd2a0bb4..c9d88a5f74 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -163,6 +163,7 @@ OpenSpaceEngine::OpenSpaceEngine(std::string programName, TransformationManager::initialize(); _documentationEngine->addDocumentation(ConfigurationManager::Documentation()); + _documentationEngine->addDocumentation(Scene::Documentation()); } OpenSpaceEngine::~OpenSpaceEngine() { @@ -415,9 +416,9 @@ bool OpenSpaceEngine::initialize() { const std::string LuaDocumentationFile = ConfigurationManager::KeyLuaDocumentation + "." + ConfigurationManager::PartFile; - const bool hasType = configurationManager().hasKey(LuaDocumentationType); - const bool hasFile = configurationManager().hasKey(LuaDocumentationFile); - if (hasType && hasFile) { + const bool hasLuaDocType = configurationManager().hasKey(LuaDocumentationType); + const bool hasLuaDocFile = configurationManager().hasKey(LuaDocumentationFile); + if (hasLuaDocType && hasLuaDocFile) { std::string luaDocumentationType; configurationManager().getValue(LuaDocumentationType, luaDocumentationType); std::string luaDocumentationFile; @@ -427,6 +428,23 @@ bool OpenSpaceEngine::initialize() { _scriptEngine->writeDocumentation(luaDocumentationFile, luaDocumentationType); } + // If a general documentation was specified, generate it now + const std::string DocumentationType = + ConfigurationManager::KeyDocumentation + '.' + ConfigurationManager::PartType; + const std::string DocumentationFile = + ConfigurationManager::KeyDocumentation + '.' + ConfigurationManager::PartFile; + + const bool hasDocumentationType = configurationManager().hasKey(DocumentationType); + const bool hasDocumentationFile = configurationManager().hasKey(DocumentationFile); + if (hasDocumentationType && hasDocumentationFile) { + std::string documentationType; + configurationManager().getValue(DocumentationType, documentationType); + std::string documentationFile; + configurationManager().getValue(DocumentationFile, documentationFile); + documentationFile = absPath(documentationFile); + _documentationEngine->writeDocumentation(documentationFile, documentationType); + } + bool disableMasterRendering = false; configurationManager().getValue( ConfigurationManager::KeyDisableMasterRendering, disableMasterRendering); diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index 61752e8a93..2df305fe3a 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -137,8 +137,6 @@ RenderEngine::RenderEngine() 12, -1 }; - - OsEng.documentationEngine().addDocumentation(Scene::Documentation()); } RenderEngine::~RenderEngine() { From 75651224a700595397525a3319a0b7000a9e026e Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 15 Sep 2016 18:58:22 +0200 Subject: [PATCH 71/92] Move documentation generation to DocumentationEngine Split Verifiers documentation method into documentation and type --- .../openspace/documentation/documentation.h | 4 +- include/openspace/documentation/verifier.h | 21 +++++---- include/openspace/documentation/verifier.inl | 42 ++++++++--------- src/documentation/documentation.cpp | 23 ++-------- src/documentation/documentationengine.cpp | 46 ++++++++++++++++++- src/documentation/verifier.cpp | 42 ++++++++++++----- 6 files changed, 113 insertions(+), 65 deletions(-) diff --git a/include/openspace/documentation/documentation.h b/include/openspace/documentation/documentation.h index 2d18c37249..746cd8d1d5 100644 --- a/include/openspace/documentation/documentation.h +++ b/include/openspace/documentation/documentation.h @@ -56,7 +56,7 @@ struct DocumentationEntry { Optional optional = Optional::No); std::string key; - std::shared_ptr tester; + std::shared_ptr verifier; bool optional; std::string documentation; }; @@ -76,8 +76,6 @@ TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& di void testSpecificationAndThrow(const Documentation& doc, const ghoul::Dictionary& dictionary, std::string component); -std::string generateDocumentation(const Documentation& d); - } // namespace documentation using documentation::Documentation; diff --git a/include/openspace/documentation/verifier.h b/include/openspace/documentation/verifier.h index d6ca25dac4..f4fcbc4ca6 100644 --- a/include/openspace/documentation/verifier.h +++ b/include/openspace/documentation/verifier.h @@ -36,7 +36,8 @@ struct Verifier { virtual bool test(const ghoul::Dictionary& dict, const std::string& key) const; - virtual std::string documentation() const = 0; + virtual std::string type() const = 0; + virtual std::string documentation() const; }; // General verifiers @@ -48,25 +49,25 @@ struct TemplateVerifier : public Verifier { struct BoolVerifier : public TemplateVerifier { bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string documentation() const override; + std::string type() const override; }; struct DoubleVerifier : public TemplateVerifier { bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string documentation() const override; + std::string type() const override; }; struct IntVerifier : public TemplateVerifier { bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string documentation() const override; + std::string type() const override; }; struct StringVerifier : public TemplateVerifier { bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string documentation() const override; + std::string type() const override; }; struct TableVerifier : public TemplateVerifier { @@ -74,7 +75,7 @@ struct TableVerifier : public TemplateVerifier { TestResult operator()(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string documentation() const override; + std::string type() const override; std::vector doc; }; @@ -85,21 +86,21 @@ template struct Vector2Verifier : public TemplateVerifier>, public VectorVerifier { bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string documentation() const override; + std::string type() const override; }; template struct Vector3Verifier : public TemplateVerifier>, public VectorVerifier { bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string documentation() const override; + std::string type() const override; }; template struct Vector4Verifier : public TemplateVerifier>, public VectorVerifier { bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string documentation() const override; + std::string type() const override; }; // Operator Verifiers @@ -277,6 +278,7 @@ struct AndVerifier : public Verifier { bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + std::string type() const override; std::string documentation() const override; std::shared_ptr a; @@ -288,6 +290,7 @@ struct OrVerifier : public Verifier { bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + std::string type() const override; std::string documentation() const override; std::shared_ptr a; diff --git a/include/openspace/documentation/verifier.inl b/include/openspace/documentation/verifier.inl index 040a0b09e7..bfc155dae8 100644 --- a/include/openspace/documentation/verifier.inl +++ b/include/openspace/documentation/verifier.inl @@ -37,10 +37,10 @@ bool Vector2Verifier::test(const ghoul::Dictionary& d, const std::string& k) } template -std::string Vector2Verifier::documentation() const { +std::string Vector2Verifier::type() const { using namespace std::string_literals; - return "Type: Vector2<"s + typeid(T).name() + ">"; + return "Vector2<"s + typeid(T).name() + ">"; } template @@ -49,10 +49,10 @@ bool Vector3Verifier::test(const ghoul::Dictionary& d, const std::string& k) } template -std::string Vector3Verifier::documentation() const { +std::string Vector3Verifier::type() const { using namespace std::string_literals; - return "Type: Vector3<"s + typeid(T).name() + ">"; + return "Vector3<"s + typeid(T).name() + ">"; } template @@ -61,10 +61,10 @@ bool Vector4Verifier::test(const ghoul::Dictionary& d, const std::string& k) } template -std::string Vector4Verifier::documentation() const { +std::string Vector4Verifier::type() const { using namespace std::string_literals; - return "Type: Vector4<"s + typeid(T).name() + ">"; + return "Vector4<"s + typeid(T).name() + ">"; } template @@ -80,7 +80,7 @@ bool LessVerifier::test(const ghoul::Dictionary& dict, const std::string& key template std::string LessVerifier::documentation() const { - return T::documentation() + '\n' + "Less than: " + std::to_string(value); + return "Less than: " + std::to_string(value); } @@ -96,7 +96,7 @@ bool LessEqualVerifier::test(const ghoul::Dictionary& dict, const std::string template std::string LessEqualVerifier::documentation() const { - return T::documentation() + '\n' + "Less or equal to: " + std::to_string(value); + return "Less or equal to: " + std::to_string(value); } template @@ -111,7 +111,7 @@ bool GreaterVerifier::test(const ghoul::Dictionary& dict, const std::string& template std::string GreaterVerifier::documentation() const { - return T::documentation() + '\n' + "Greater than: " + std::to_string(value); + return "Greater than: " + std::to_string(value); } template @@ -126,7 +126,7 @@ bool GreaterEqualVerifier::test(const ghoul::Dictionary& dict, const std::str template std::string GreaterEqualVerifier::documentation() const { - return T::documentation() + '\n' + "Greater or equal to: " + std::to_string(value); + return "Greater or equal to: " + std::to_string(value); } template @@ -141,7 +141,7 @@ bool EqualVerifier::test(const ghoul::Dictionary& dict, const std::string& ke template std::string EqualVerifier::documentation() const { - return T::documentation() + '\n' + "Equal to: " + std::to_string(value); + return "Equal to: " + std::to_string(value); } template @@ -156,7 +156,7 @@ bool UnequalVerifier::test(const ghoul::Dictionary& dict, const std::string& template std::string UnequalVerifier::documentation() const { - return T::documentation() + '\n' + "Unequal to: " + std::to_string(value); + return "Unequal to: " + std::to_string(value); } template @@ -179,7 +179,7 @@ bool InListVerifier::test(const ghoul::Dictionary& dict, const std::string& k template std::string InListVerifier::documentation() const { - std::string result = T::documentation() + '\n' + "In list {"; + std::string result = "In list { "; std::stringstream s; std::copy(values.begin(), values.end(), std::ostream_iterator(s, ",")); @@ -188,7 +188,7 @@ std::string InListVerifier::documentation() const { // We need to remove a trailing ',' at the end of the string result += joined.substr(0, joined.size() - 1); - result += "}"; + result += " }"; return result; } @@ -212,7 +212,7 @@ bool NotInListVerifier::test(const ghoul::Dictionary& dict, const std::string template std::string NotInListVerifier::documentation() const { - std::string result = T::documentation() + '\n' + "Not in list {"; + std::string result = "Not in list { "; std::stringstream s; std::copy(values.begin(), values.end(), std::ostream_iterator(s, ",")); @@ -222,7 +222,7 @@ std::string NotInListVerifier::documentation() const { result += joined.substr(0, joined.size() - 1); - result += "}"; + result += " }"; return result; } @@ -247,8 +247,8 @@ bool InRangeVerifier::test(const ghoul::Dictionary& d, const std::string& key template std::string InRangeVerifier::documentation() const { - return T::documentation() + '\n' + "In range: (" + std::to_string(lower) + "," + - std::to_string(upper) + ")"; + return "In range: ( " + std::to_string(lower) + "," + + std::to_string(upper) + " )"; } template @@ -272,8 +272,8 @@ bool NotInRangeVerifier::test(const ghoul::Dictionary& d, const std::string& template std::string NotInRangeVerifier::documentation() const { - return T::documentation() + '\n' + "Not in range: (" + std::to_string(lower) + "," + - std::to_string(upper) + ")"; + return "Not in range: ( " + std::to_string(lower) + "," + + std::to_string(upper) + " )"; } @@ -291,7 +291,7 @@ bool AnnotationVerifier::test(const ghoul::Dictionary& dict, template std::string AnnotationVerifier::documentation() const { - return T::documentation() + '\n' + annotation; + return annotation; } } // namespace documentation diff --git a/src/documentation/documentation.cpp b/src/documentation/documentation.cpp index 7c1a917adf..5f91fc37d0 100644 --- a/src/documentation/documentation.cpp +++ b/src/documentation/documentation.cpp @@ -48,7 +48,7 @@ SpecificationError::SpecificationError(TestResult result, std::string component) DocumentationEntry::DocumentationEntry(std::string key, Verifier* t, std::string doc, Optional optional) : key(std::move(key)) - , tester(std::move(t)) + , verifier(std::move(t)) , documentation(std::move(doc)) , optional(optional) {} @@ -66,7 +66,7 @@ TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& di for (const auto& p : d.entries) { if (p.key == Wildcard) { for (const std::string& key : dictionary.keys()) { - Verifier& verifier = *(p.tester); + Verifier& verifier = *(p.verifier); TestResult res = verifier(dictionary, key); if (!res.success) { result.success = false; @@ -84,7 +84,7 @@ TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& di // if the key exists, it has to be correct, however continue; } - Verifier& verifier = *(p.tester); + Verifier& verifier = *(p.verifier); TestResult res = verifier(dictionary, p.key); if (!res.success) { result.success = false; @@ -124,22 +124,5 @@ void testSpecificationAndThrow(const Documentation& doc, } } - -std::string generateDocumentation(const Documentation& d) { - using namespace std::string_literals; - std::string result; - - result += "Name: "s + d.name + '\n'; - for (const auto& p : d.entries) { - result += p.key + '\n'; - result += "Optional: "s + (p.optional ? "true" : "false") + '\n'; - result += p.tester->documentation() + '\n'; - result += '\n'; - result += p.documentation + '\n'; - } - - return result; -} - } // namespace documentation } // namespace openspace diff --git a/src/documentation/documentationengine.cpp b/src/documentation/documentationengine.cpp index d3067f4179..bac6684b08 100644 --- a/src/documentation/documentationengine.cpp +++ b/src/documentation/documentationengine.cpp @@ -24,6 +24,8 @@ #include +#include + #include #include @@ -31,6 +33,47 @@ namespace openspace { namespace documentation { + +std::string generateTextDocumentation(const Documentation& d, int& indentLevel) { + using namespace std::string_literals; + + auto indentMessage = [&indentLevel](std::string prefix, std::string msg) { + if (msg.empty()) { + return ""s; + } + else { + return std::string(indentLevel, '\t') + prefix + ": " + msg + '\n'; + } + }; + std::string result; + + result += indentMessage("Name", d.name); + if (!d.name.empty()) { + ++indentLevel; + } + for (const auto& p : d.entries) { + result += indentMessage("Key", (p.key == "*") ? p.key : "\"" + p.key + "\""); + result += indentMessage("Optional", (p.optional ? "true" : "false")); + result += indentMessage("Type", p.verifier->type()); + result += indentMessage("Restrictions", p.verifier->documentation()); + TableVerifier* tv = dynamic_cast(p.verifier.get()); + if (tv) { + // We have a TableVerifier, so we need to recurse + ++indentLevel; + result += generateTextDocumentation(tv->doc, indentLevel); + result = result.substr(0, result.size() - 2); + --indentLevel; + } + result += indentMessage("Documentation", p.documentation); + result += "\n\n"; + } + if (!d.name.empty()) { + --indentLevel; + } + + return result; +} + void DocumentationEngine::writeDocumentation(const std::string& f, const std::string& t) { if (t == "text") { std::ofstream file; @@ -38,7 +81,8 @@ void DocumentationEngine::writeDocumentation(const std::string& f, const std::st file.open(f); for (const Documentation& d : _documentations) { - file << documentation::generateDocumentation(d) << std::endl << std::endl; + int indent = 0; + file << documentation::generateTextDocumentation(d, indent) << std::endl << std::endl; } } } diff --git a/src/documentation/verifier.cpp b/src/documentation/verifier.cpp index 8e8c04e850..ddbeab184c 100644 --- a/src/documentation/verifier.cpp +++ b/src/documentation/verifier.cpp @@ -90,20 +90,24 @@ bool Verifier::test(const ghoul::Dictionary& dict, const std::string& key) const return false; }; +std::string Verifier::documentation() const { + return ""; +} + bool BoolVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { return dict.hasKeyAndValue(key); } -std::string BoolVerifier::documentation() const { - return "Type: Boolean"; +std::string BoolVerifier::type() const { + return "Boolean"; } bool DoubleVerifier::test(const ghoul::Dictionary & dict, const std::string & key) const { return dict.hasKeyAndValue(key); } -std::string DoubleVerifier::documentation() const { - return "Type: Double"; +std::string DoubleVerifier::type() const { + return "Double"; } bool IntVerifier::test(const ghoul::Dictionary & dict, const std::string & key) const { @@ -124,16 +128,16 @@ bool IntVerifier::test(const ghoul::Dictionary & dict, const std::string & key) } } -std::string IntVerifier::documentation() const { - return "Type: Integer"; +std::string IntVerifier::type() const { + return "Integer"; } bool StringVerifier::test(const ghoul::Dictionary & dict, const std::string & key) const { return dict.hasKeyAndValue(key); } -std::string StringVerifier::documentation() const { - return "Type: String"; +std::string StringVerifier::type() const { + return "String"; } TableVerifier::TableVerifier(std::vector d) @@ -156,19 +160,26 @@ TestResult TableVerifier::operator()(const ghoul::Dictionary& dict, return { dict.hasKeyAndValue(key), { key } }; } -std::string TableVerifier::documentation() const { - return "Type: Table" + '\n' + generateDocumentation(doc); +std::string TableVerifier::type() const { + return "Table"; } AndVerifier::AndVerifier(Verifier* a, Verifier* b) : a(a) , b(b) -{} +{ + ghoul_assert(a->type() == b->type(), "Cannot use AndVerifier with different types"); +} bool AndVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { return a->test(dict, key) && b->test(dict, key); } +std::string AndVerifier::type() const { + // It does not matter which type we choose as they both have to be the same + return a->type(); +} + std::string AndVerifier::documentation() const { return a->documentation() + " and " + b->documentation(); } @@ -182,6 +193,15 @@ bool OrVerifier::test(const ghoul::Dictionary& dict, const std::string& key) con return a->test(dict, key) || b->test(dict, key); } +std::string OrVerifier::type() const { + if (a->type() != b->type()) { + return a->type() + " or " + b->type(); + } + else { + return a->type(); + } +} + std::string OrVerifier::documentation() const { return a->documentation() + " or " + b->documentation(); } From 6f5ef8d66cc6db20a8717cda5ac7d1c8ab9a2578 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Fri, 16 Sep 2016 09:57:07 +0200 Subject: [PATCH 72/92] Add ability to generate JSON for general documentation --- src/documentation/documentationengine.cpp | 53 ++++++++++++++++++++++- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/src/documentation/documentationengine.cpp b/src/documentation/documentationengine.cpp index bac6684b08..91366a7a4e 100644 --- a/src/documentation/documentationengine.cpp +++ b/src/documentation/documentationengine.cpp @@ -55,7 +55,6 @@ std::string generateTextDocumentation(const Documentation& d, int& indentLevel) result += indentMessage("Key", (p.key == "*") ? p.key : "\"" + p.key + "\""); result += indentMessage("Optional", (p.optional ? "true" : "false")); result += indentMessage("Type", p.verifier->type()); - result += indentMessage("Restrictions", p.verifier->documentation()); TableVerifier* tv = dynamic_cast(p.verifier.get()); if (tv) { // We have a TableVerifier, so we need to recurse @@ -64,6 +63,9 @@ std::string generateTextDocumentation(const Documentation& d, int& indentLevel) result = result.substr(0, result.size() - 2); --indentLevel; } + else { + result += indentMessage("Restrictions", p.verifier->documentation()); + } result += indentMessage("Documentation", p.documentation); result += "\n\n"; } @@ -74,6 +76,34 @@ std::string generateTextDocumentation(const Documentation& d, int& indentLevel) return result; } +std::string generateJsonDocumentation(const Documentation& d) { + std::stringstream result; + result << "{"; + + result << "\"name\": \"" << d.name << "\","; + result << "\"entries\": ["; + for (const auto& p : d.entries) { + result << "{"; + result << "\"key\": \"" << p.key << "\","; + result << "\"optional\": \"" << (p.optional ? "true" : "false") << "\","; + result << "\"type\": \"" << p.verifier->type() << "\","; + TableVerifier* tv = dynamic_cast(p.verifier.get()); + if (tv) { + // We have a TableVerifier, so we need to recurse + result << "\"restrictions\": " << generateJsonDocumentation(tv->doc) << ","; + } + else { + result << "\"restrictions\": \"" << p.verifier->documentation() << "\","; + } + result << "},"; + } + + result << ']'; + result << "}"; + + return result.str(); +} + void DocumentationEngine::writeDocumentation(const std::string& f, const std::string& t) { if (t == "text") { std::ofstream file; @@ -82,9 +112,28 @@ void DocumentationEngine::writeDocumentation(const std::string& f, const std::st for (const Documentation& d : _documentations) { int indent = 0; - file << documentation::generateTextDocumentation(d, indent) << std::endl << std::endl; + file << documentation::generateTextDocumentation(d, indent) << "\n\n"; } } + else if (t == "html") { + std::ofstream file; + file.exceptions(~std::ofstream::goodbit); + file.open(f); + + std::stringstream json; + json << "["; + + for (const Documentation& d : _documentations) { + json << generateJsonDocumentation(d); + json << ","; + } + + json << "]"; + + std::string jsonText = json.str(); + + file << jsonText; + } } void DocumentationEngine::addDocumentation(Documentation doc) { From b03661b75562a3d1f1e6c2c88a93b6dcfe99e542 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Fri, 16 Sep 2016 11:15:48 +0200 Subject: [PATCH 73/92] Fix spelling in verifier comments --- include/openspace/documentation/verifier.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/openspace/documentation/verifier.h b/include/openspace/documentation/verifier.h index f4fcbc4ca6..4d70d895e8 100644 --- a/include/openspace/documentation/verifier.h +++ b/include/openspace/documentation/verifier.h @@ -110,7 +110,7 @@ struct LessVerifier : public T { static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); - static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + static_assert(!std::is_base_of_v, "T cannot be VectorVerifier"); LessVerifier(typename T::Type value); @@ -126,7 +126,7 @@ struct LessEqualVerifier : public T { static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); - static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + static_assert(!std::is_base_of_v, "T cannot be VectorVerifier"); LessEqualVerifier(typename T::Type value); @@ -142,7 +142,7 @@ struct GreaterVerifier : public T { static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); - static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + static_assert(!std::is_base_of_v, "T cannot be VectorVerifier"); GreaterVerifier(typename T::Type value); @@ -158,7 +158,7 @@ struct GreaterEqualVerifier : public T { static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); - static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + static_assert(!std::is_base_of_v, "T cannot be VectorVerifier"); GreaterEqualVerifier(typename T::Type value); @@ -229,7 +229,7 @@ struct InRangeVerifier : public T { static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); - static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + static_assert(!std::is_base_of_v, "T cannot be VectorVerifier"); InRangeVerifier(typename T::Type lower, typename T::Type upper); @@ -246,7 +246,7 @@ struct NotInRangeVerifier : public T { static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); - static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + static_assert(!std::is_base_of_v, "T cannot be VectorVerifier"); NotInRangeVerifier(typename T::Type lower, typename T::Type upper); From 022bf463130b91007e6b2c4b767da3e897164fde Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Fri, 16 Sep 2016 11:16:08 +0200 Subject: [PATCH 74/92] Outputting HTML for the LuaScripting --- src/scripting/scriptengine.cpp | 55 ++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/scripting/scriptengine.cpp b/src/scripting/scriptengine.cpp index 5f396d68f9..64fbb91be7 100644 --- a/src/scripting/scriptengine.cpp +++ b/src/scripting/scriptengine.cpp @@ -566,6 +566,7 @@ void ScriptEngine::writeDocumentation(const std::string& filename, const std::st file.exceptions(~std::ofstream::goodbit); file.open(filename); +#ifdef JSON // Create JSON std::stringstream json; json << "["; @@ -589,7 +590,61 @@ void ScriptEngine::writeDocumentation(const std::string& filename, const std::st std::string jsonText = json.str(); +#else + std::stringstream html; + html << "\n" + << "\t\n" + << "\t\tScript Log\n" + << "\t\n" + << "\n" + << "\n" + << "\t\n\n" + << "\t\n" + << "\t\t\n" + << "\t\t\t\n" + << "\t\t\t\n" + << "\t\t\n" + << "\t\t\n" + << "\t\t\t\n" + << "\t\t\t\n" + << "\t\t\t\n" + << "\t\t\n" + << "\t\n" + << "\t\n"; + + + + for (const LuaLibrary& l : _registeredLibraries) { + html << "\t\n"; + + if (l.name.empty()) { + html << "\t\t\n"; + } + else { + html << "\t\t\n"; + } + html << "\t\t\n" + << "\t\"; + + for (const LuaLibrary::Function& f : l.functions) { + html << "\t\n" + << "\t\t\n" + << "\t\t\n" + << "\t\t\n" + << "\t\t\n" + << "\t\n"; + } + + html << "\t\n"; + } + + html << "\t\n" + << "
Script Log
LibraryFunctions
NameArgumentsHelp
openspaceopenspace." << l.name << "
" << f.name << "" << f.argumentText << "" << f.helpText << "
\n" + << ""; + + file << html.str(); +#endif } else { throw ghoul::RuntimeError("Undefined type '" + type + "' for Lua documentation"); From 76f1c7166af230ea1daf004fe88a237298ccf56c Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Fri, 16 Sep 2016 11:27:59 +0200 Subject: [PATCH 75/92] Add HTML output to keybindings --- src/interaction/interactionhandler.cpp | 33 ++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/interaction/interactionhandler.cpp b/src/interaction/interactionhandler.cpp index 0c8d324daf..1d2f4f1181 100644 --- a/src/interaction/interactionhandler.cpp +++ b/src/interaction/interactionhandler.cpp @@ -967,6 +967,7 @@ void InteractionHandler::writeKeyboardDocumentation(const std::string& type, con f.exceptions(~std::ofstream::goodbit); f.open(absPath(file)); +#ifdef JSON std::stringstream json; json << "["; for (const auto& p : _keyLua) { @@ -979,6 +980,38 @@ void InteractionHandler::writeKeyboardDocumentation(const std::string& type, con std::string jsonText = json.str(); +#else + std::stringstream html; + + html << "\n" + << "\t\n" + << "\t\tKey Bindings\n" + << "\t\n" + << "\n" + << "\n" + << "\t\n\n" + << "\t\n" + << "\t\t\n" + << "\t\t\t\n" + << "\t\t\t\n" + << "\t\t\n" + << "\t\n" + << "\t\n"; + + for (const auto& p : _keyLua) { + html << "\t\t\n" + << "\t\t\t\n" + << "\t\t\t\n" + << "\t\t\n"; + } + + html << "\t\n" + << "
Key Bindings
KeyBinding
" << std::to_string(p.first) << "" << p.second << "
\n" + << ""; + + f << html.str(); +#endif + } else { throw ghoul::RuntimeError( From 7f0e0aafcc9e426de5691358bd8347a7a39803fe Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Fri, 16 Sep 2016 11:39:26 +0200 Subject: [PATCH 76/92] Writing property documentation as html --- src/scene/scene.cpp | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp index 85e71717df..277fd54732 100644 --- a/src/scene/scene.cpp +++ b/src/scene/scene.cpp @@ -464,6 +464,7 @@ void Scene::writePropertyDocumentation(const std::string& filename, const std::s file.exceptions(~std::ofstream::goodbit); file.open(filename); +#ifdef JSON // Create JSON std::function createJson = [&createJson](properties::PropertyOwner* owner) -> std::string @@ -476,6 +477,7 @@ void Scene::writePropertyDocumentation(const std::string& filename, const std::s for (properties::Property* p : owner->properties()) { json << "{"; json << "\"id\": \"" << p->identifier() << "\","; + json << "\"type\": \"" << p->className() << "\","; json << "\"fullyQualifiedId\": \"" << p->fullyQualifiedIdentifier() << "\","; json << "\"guiName\": \"" << p->guiName() << "\","; json << "},"; @@ -502,6 +504,45 @@ void Scene::writePropertyDocumentation(const std::string& filename, const std::s json << "]"; std::string jsonText = json.str(); +#else + std::stringstream html; + html << "\n" + << "\t\n" + << "\t\tProperties\n" + << "\t\n" + << "\n" + << "\n" + << "\t\n\n" + << "\t\n" + << "\t\t\n" + << "\t\t\t\n" + << "\t\t\t\n" + << "\t\t\t\n" + << "\t\t\n" + << "\t\n" + << "\t\n"; + + for (SceneGraphNode* node : _graph.nodes()) { + for (properties::Property* p : node->propertiesRecursive()) { + html << "\t\t\n" + << "\t\t\t\n" + << "\t\t\t\n" + << "\t\t\t\n" + << "\t\t\n"; + } + + if (!node->propertiesRecursive().empty()) { + html << "\t\n"; + } + + } + + html << "\t\n" + << "
Properties
IDTypeDescription
" << p->fullyQualifiedIdentifier() << "" << p->className() << "" << p->guiName() << "
\n" + << ";"; + + file << html.str(); +#endif } else From 17a65e381608815db854b3bb3e68bcc7a945a0c3 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Fri, 16 Sep 2016 11:56:15 +0200 Subject: [PATCH 77/92] Writing general Documentation as HTML Add HTML to gitignore Set default documentation to HTML --- Documentation.html | 447 ++++++++++++++++++++++ openspace.cfg | 16 +- src/documentation/documentationengine.cpp | 55 ++- 3 files changed, 509 insertions(+), 9 deletions(-) create mode 100644 Documentation.html diff --git a/Documentation.html b/Documentation.html new file mode 100644 index 0000000000..347802bc8d --- /dev/null +++ b/Documentation.html @@ -0,0 +1,447 @@ + + + Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OpenSpace Configuration
KeyOptionalTypeRestrictionsDocumentation
SGCTConfigfalseStringA valid SGCT configuration file
ScenefalseStringA valid scene file as described in the Scene documentation
PathstrueTable + + + + + + + + + + + + + + + + + + +
KeyOptionalTypeRestrictionsDocumentation
*falseString
+
FontstrueTable + + + + + + + + + + + + + + + + + + +
KeyOptionalTypeRestrictionsDocumentation
*falseString
+
LoggingtrueTable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyOptionalTypeRestrictionsDocumentation
LogLeveltrueStringIn list { Debug,Info,Warning,Error,Fatal,None }
ImmediateFlushtrueBoolean
LogstrueTable + + + + + + + + + + + + + + + + + + +
KeyOptionalTypeRestrictionsDocumentation
*trueTable + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyOptionalTypeRestrictionsDocumentation
TypefalseStringIn list { text,html }
FilefalseString
AppendtrueBoolean
+
+
CapabilitiesVerbositytrueStringIn list { None,Minimal,Default,Full }
+
LuaDocumentationtrueTable + + + + + + + + + + + + + + + + + + + + + + + +
KeyOptionalTypeRestrictionsDocumentation
TypefalseStringIn list { text,html }
FilefalseString
+
PropertyDocumentationtrueTable + + + + + + + + + + + + + + + + + + + + + + + +
KeyOptionalTypeRestrictionsDocumentation
TypefalseStringIn list { text,html }
FilefalseString
+
ScriptLogtrueTable + + + + + + + + + + + + + + + + + + + + + + + +
KeyOptionalTypeRestrictionsDocumentation
TypefalseStringIn list { text }
FilefalseString
+
KeyboardShortcutstrueTable + + + + + + + + + + + + + + + + + + + + + + + +
KeyOptionalTypeRestrictionsDocumentation
TypefalseStringIn list { text,html }
FilefalseString
+
DocumentationtrueTable + + + + + + + + + + + + + + + + + + + + + + + +
KeyOptionalTypeRestrictionsDocumentation
TypefalseStringIn list { text,html }
FilefalseString
+
ShutdownCountdowntrueDoubleGreater or equal to: 0.000000
DownloadRequestURLtrueString or Table or
RenderingMethodtrueStringIn list { Framebuffer,ABuffer }
DisableRenderingOnMastertrueBoolean
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Scene Description
KeyOptionalTypeRestrictionsDocumentation
ScenePathtrueString
CommonFoldertrueStringA valid scene module folder
CameratrueTable + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyOptionalTypeRestrictionsDocumentation
FocusfalseStringA valid object in the scene
PositiontrueVector3
RotationtrueVector4
+
ModulesfalseTable + + + + + + + + + + + + + + + + + + +
KeyOptionalTypeRestrictionsDocumentation
*falseStringLoadable module folders. This means that they either have to point to a folder that contains a ModuleFile or a folder which contains other folders that eventually contain ModuleFile. This second recursive approach is useful for grouping modules into logical units.
+
+ + + + + + + + + + + + + + + + + + + +
Static Scaling
KeyOptionalTypeRestrictionsDocumentation
ScalefalseDouble
+ + diff --git a/openspace.cfg b/openspace.cfg index df4f338ec5..26d17c9762 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -41,24 +41,24 @@ return { CapabilitiesVerbosity = "Full" }, LuaDocumentation = { - Type = "text", - File = "${BASE_PATH}/LuaScripting.txt" + Type = "html", + File = "${BASE_PATH}/LuaScripting.html" }, PropertyDocumentation = { - Type = "text", - File = "${BASE_PATH}/Properties.txt" + Type = "html", + File = "${BASE_PATH}/Properties.html" }, ScriptLog = { Type = "text", File = "${BASE_PATH}/ScriptLog.txt" }, KeyboardShortcuts = { - Type = "text", - File = "${BASE_PATH}/KeyboardMapping.txt" + Type = "html", + File = "${BASE_PATH}/KeyboardMapping.html" }, Documentation = { - Type = "text", - File = "${BASE_PATH}/Documentation.txt" + Type = "html", + File = "${BASE_PATH}/Documentation.html" }, ShutdownCountdown = 3, DownloadRequestURL = "http://130.236.132.168/request.cgi", diff --git a/src/documentation/documentationengine.cpp b/src/documentation/documentationengine.cpp index 91366a7a4e..7d32f09a4a 100644 --- a/src/documentation/documentationengine.cpp +++ b/src/documentation/documentationengine.cpp @@ -104,6 +104,42 @@ std::string generateJsonDocumentation(const Documentation& d) { return result.str(); } +std::string generateHtmlDocumentation(const Documentation& d) { + std::stringstream html; + html << "\n" + << "\t\n\n" + << "\t\n" + << "\t\t\n" + << "\t\t\t\n" + << "\t\t\t\n" + << "\t\t\t\n" + << "\t\t\t\n" + << "\t\t\t\n" + << "\t\t\n" + << "\t\n" + << "\t\n"; + + for (const auto& p : d.entries) { + html << "\t\n" + << "\t\t\n" + << "\t\t\n" + << "\t\t\n"; + TableVerifier* tv = dynamic_cast(p.verifier.get()); + if (tv) { + // We have a TableVerifier, so we need to recurse + html << "\t\t\n"; + } + else { + html << "\t\t\n"; + } + + } + + html << "\t\n" + << "
" << d.name << "
KeyOptionalTypeRestrictionsDocumentation
" << p.key << "" << (p.optional ? "true" : "false") << "" << p.verifier->type() << "" << generateHtmlDocumentation(tv->doc) << "" << p.verifier->documentation() << "
\n"; + return html.str(); +} + void DocumentationEngine::writeDocumentation(const std::string& f, const std::string& t) { if (t == "text") { std::ofstream file; @@ -120,6 +156,7 @@ void DocumentationEngine::writeDocumentation(const std::string& f, const std::st file.exceptions(~std::ofstream::goodbit); file.open(f); +#ifdef JSON std::stringstream json; json << "["; @@ -131,8 +168,24 @@ void DocumentationEngine::writeDocumentation(const std::string& f, const std::st json << "]"; std::string jsonText = json.str(); +#else + std::stringstream html; - file << jsonText; + html << "\n" + << "\t\n" + << "\t\tDocumentation\n" + << "\t\n" + << "\n"; + + for (const Documentation& d : _documentations) { + html << generateHtmlDocumentation(d); + } + + html << "\n"; + html << "\n"; + + file << html.str(); +#endif } } From 24e5146a8e124e6463bc422eacc91bdc7b59b58f Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Fri, 16 Sep 2016 12:24:47 +0200 Subject: [PATCH 78/92] Updating HTML generation for general documentation --- .gitignore | 1 + src/documentation/documentationengine.cpp | 61 +++++++++++++++++------ 2 files changed, 46 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index 3b94161ec7..9ec2a23d14 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,7 @@ shaders/ABuffer/constants.hglsl LuaScripting.txt Properties.txt log.html +Documentation.html data/scene/rosetta/67P/obj/67P_rotated_5_130.obj data/spice/NewHorizonsKernels/ data/scene/newhorizons/pluto/pluto/textures/ diff --git a/src/documentation/documentationengine.cpp b/src/documentation/documentationengine.cpp index 7d32f09a4a..2489730b41 100644 --- a/src/documentation/documentationengine.cpp +++ b/src/documentation/documentationengine.cpp @@ -106,37 +106,44 @@ std::string generateJsonDocumentation(const Documentation& d) { std::string generateHtmlDocumentation(const Documentation& d) { std::stringstream html; - html << "\n" - << "\t\n\n" - << "\t\n" - << "\t\t\n" - << "\t\t\t\n" - << "\t\t\t\n" - << "\t\t\t\n" - << "\t\t\t\n" - << "\t\t\t\n" - << "\t\t\n" - << "\t\n" - << "\t\n"; - + + html << "\t\n" + << "\t\t\n"; + for (const auto& p : d.entries) { html << "\t\n" + << "\t\t\n" << "\t\t\n" << "\t\t\n" << "\t\t\n"; TableVerifier* tv = dynamic_cast(p.verifier.get()); if (tv) { // We have a TableVerifier, so we need to recurse - html << "\t\t\n"; + html << "\n"; } else { html << "\t\t\n"; } + html << "\t\t\n" + << "\t\n"; } - html << "\t\n" - << "
" << d.name << "
KeyOptionalTypeRestrictionsDocumentation
" << d.name << "
" << p.key << "" << (p.optional ? "true" : "false") << "" << p.verifier->type() << "" << generateHtmlDocumentation(tv->doc) << "\n" + << "\t\n" + << "\t\t\n" + << "\t\t\t\n" + << "\t\t\t\n" + << "\t\t\t\n" + << "\t\t\t\n" + << "\t\t\t\n" + << "\t\t\t\n" + << "\t\t\n" + << "\t\n" + << "\t\n" + << generateHtmlDocumentation(tv->doc) + << "\t\n" + << "
KeyOptionalTypeRestrictionsDocumentation
\n" + << "
" << p.verifier->documentation() << "" << p.documentation << "
\n"; return html.str(); } @@ -177,10 +184,32 @@ void DocumentationEngine::writeDocumentation(const std::string& f, const std::st << "\t\n" << "\n"; + + html << "\n" + << "\t\n\n" + << "\t\n" + << "\t\t\n" + << "\t\t\t\n" + << "\t\t\n" + << "\t\t\n" + << "\t\t\t\n" + << "\t\t\t\n" + << "\t\t\t\n" + << "\t\t\t\n" + << "\t\t\t\n" + << "\t\t\n" + << "\t\n" + << "\t\n"; + for (const Documentation& d : _documentations) { html << generateHtmlDocumentation(d); + + html << "\t\n"; } + html << "\t\n" + << "
Documentation
Name
KeyOptionalTypeRestrictionsDocumentation

\n"; + html << "\n"; html << "\n"; From 2fa6471e98c3637166ae76ab00c187b46b6ea4e2 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Fri, 16 Sep 2016 16:53:50 +0200 Subject: [PATCH 79/92] Allow Documentations to be exhaustive to not allow extra dictionaries --- .../openspace/documentation/documentation.h | 5 +- include/openspace/documentation/verifier.h | 3 +- src/documentation/documentation.cpp | 33 +++++++++- src/documentation/verifier.cpp | 5 +- tests/test_documentation.inl | 64 +++++++++++++++++++ 5 files changed, 103 insertions(+), 7 deletions(-) diff --git a/include/openspace/documentation/documentation.h b/include/openspace/documentation/documentation.h index 746cd8d1d5..91f37c0648 100644 --- a/include/openspace/documentation/documentation.h +++ b/include/openspace/documentation/documentation.h @@ -39,6 +39,7 @@ namespace documentation { struct Verifier; using Optional = ghoul::Boolean; +using Exhaustive = ghoul::Boolean; struct TestResult { bool success; @@ -64,11 +65,13 @@ struct DocumentationEntry { using DocumentationEntries = std::vector; struct Documentation { - Documentation(std::string name = "", DocumentationEntries entries = {}); + Documentation(std::string name = "", DocumentationEntries entries = {}, + Exhaustive exhaustive = Exhaustive::No); Documentation(DocumentationEntries entries); std::string name; DocumentationEntries entries; + Exhaustive exhaustive; }; diff --git a/include/openspace/documentation/verifier.h b/include/openspace/documentation/verifier.h index 4d70d895e8..cd37530e22 100644 --- a/include/openspace/documentation/verifier.h +++ b/include/openspace/documentation/verifier.h @@ -71,13 +71,14 @@ struct StringVerifier : public TemplateVerifier { }; struct TableVerifier : public TemplateVerifier { - TableVerifier(std::vector d = {}); + TableVerifier(std::vector d = {}, Exhaustive exhaustive = Exhaustive::No); TestResult operator()(const ghoul::Dictionary& dict, const std::string& key) const override; std::string type() const override; std::vector doc; + Exhaustive exhaustive; }; struct VectorVerifier {}; diff --git a/src/documentation/documentation.cpp b/src/documentation/documentation.cpp index 5f91fc37d0..b908c5d551 100644 --- a/src/documentation/documentation.cpp +++ b/src/documentation/documentation.cpp @@ -52,9 +52,11 @@ DocumentationEntry::DocumentationEntry(std::string key, Verifier* t, std::string , documentation(std::move(doc)) , optional(optional) {} -Documentation::Documentation(std::string name, DocumentationEntries entries) +Documentation::Documentation(std::string name, DocumentationEntries entries, Exhaustive exhaustive) : name(std::move(name)) - , entries(std::move(entries)) {} + , entries(std::move(entries)) + , exhaustive(std::move(exhaustive)) +{} Documentation::Documentation(DocumentationEntries entries) : Documentation("", std::move(entries)) {} @@ -97,6 +99,31 @@ TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& di } } + if (d.exhaustive) { + // If the documentation is exhaustive, we have to check if there are extra values + // in the table that are not covered by the Documentation + + for (const std::string& key : dictionary.keys()) { + auto it = std::find_if( + d.entries.begin(), + d.entries.end(), + [&key](const DocumentationEntry& entry) { + if (entry.key == Wildcard) { + return true; + } + else { + return entry.key == key; + } + } + ); + + if (it == d.entries.end()) { + result.success = false; + result.offenders.push_back(key); + } + } + } + // Remove duplicate offenders that might occur if multiple rules apply to a single // key and more than one of these rules are broken std::set uniqueOffenders( @@ -104,7 +131,7 @@ TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& di ); result.offenders = std::vector( uniqueOffenders.begin(), uniqueOffenders.end() - ); + ); return result; } diff --git a/src/documentation/verifier.cpp b/src/documentation/verifier.cpp index ddbeab184c..c1db34e868 100644 --- a/src/documentation/verifier.cpp +++ b/src/documentation/verifier.cpp @@ -140,8 +140,9 @@ std::string StringVerifier::type() const { return "String"; } -TableVerifier::TableVerifier(std::vector d) +TableVerifier::TableVerifier(std::vector d, Exhaustive exhaustive) : doc(std::move(d)) + , exhaustive(std::move(exhaustive)) {} TestResult TableVerifier::operator()(const ghoul::Dictionary& dict, @@ -149,7 +150,7 @@ TestResult TableVerifier::operator()(const ghoul::Dictionary& dict, { if (dict.hasKeyAndValue(key)) { ghoul::Dictionary d = dict.value(key); - TestResult res = testSpecification(doc, d); + TestResult res = testSpecification({ "", doc, exhaustive }, d); for (std::string& s : res.offenders) { s = key + "." + s; diff --git a/tests/test_documentation.inl b/tests/test_documentation.inl index 773088cad8..34e8d05f6b 100644 --- a/tests/test_documentation.inl +++ b/tests/test_documentation.inl @@ -639,6 +639,70 @@ TEST_F(DocumentationTest, RequiredInOptional) { EXPECT_EQ("a.b", negativeRes.offenders[0]); } +TEST_F(DocumentationTest, Exhaustive) { + using namespace openspace::documentation; + + Documentation doc { + "Test", + {{ "Int", new IntVerifier }}, + Exhaustive::Yes + }; + + ghoul::Dictionary positive { + { "Int" , 1 } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "False_Int", 1 } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(2, negativeRes.offenders.size()); + EXPECT_EQ("False_Int", negativeRes.offenders[0]); + EXPECT_EQ("Int", negativeRes.offenders[1]); + + ghoul::Dictionary negative2 { + { "Double", 2.0 } + }; + negativeRes = testSpecification(doc, negative2); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(2, negativeRes.offenders.size()); + EXPECT_EQ("Double", negativeRes.offenders[0]); + EXPECT_EQ("Int", negativeRes.offenders[1]); +} + +TEST_F(DocumentationTest, NestedExhaustive) { + using namespace openspace::documentation; + + Documentation doc { + "Test", + {{ "Table", new TableVerifier( + { { "a", new IntVerifier } }, + Exhaustive::Yes + ) + }} + }; + + ghoul::Dictionary positive { + { "Table", ghoul::Dictionary{{ "a", 1 }}} + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenders.size()); + + ghoul::Dictionary negative { + { "Table", ghoul::Dictionary{{ "b", 2.0 }}} + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(2, negativeRes.offenders.size()); + EXPECT_EQ("Table.a", negativeRes.offenders[0]); + EXPECT_EQ("Table.b", negativeRes.offenders[1]); +} + TEST_F(DocumentationTest, LessInt) { using namespace openspace::documentation; From 2c164a1098adca14a5e2927cb715a8dcb7008e5e Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Fri, 16 Sep 2016 17:01:05 +0200 Subject: [PATCH 80/92] Remove Documentation.html --- Documentation.html | 447 --------------------------------------------- 1 file changed, 447 deletions(-) delete mode 100644 Documentation.html diff --git a/Documentation.html b/Documentation.html deleted file mode 100644 index 347802bc8d..0000000000 --- a/Documentation.html +++ /dev/null @@ -1,447 +0,0 @@ - - - Documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
OpenSpace Configuration
KeyOptionalTypeRestrictionsDocumentation
SGCTConfigfalseStringA valid SGCT configuration file
ScenefalseStringA valid scene file as described in the Scene documentation
PathstrueTable - - - - - - - - - - - - - - - - - - -
KeyOptionalTypeRestrictionsDocumentation
*falseString
-
FontstrueTable - - - - - - - - - - - - - - - - - - -
KeyOptionalTypeRestrictionsDocumentation
*falseString
-
LoggingtrueTable - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KeyOptionalTypeRestrictionsDocumentation
LogLeveltrueStringIn list { Debug,Info,Warning,Error,Fatal,None }
ImmediateFlushtrueBoolean
LogstrueTable - - - - - - - - - - - - - - - - - - -
KeyOptionalTypeRestrictionsDocumentation
*trueTable - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KeyOptionalTypeRestrictionsDocumentation
TypefalseStringIn list { text,html }
FilefalseString
AppendtrueBoolean
-
-
CapabilitiesVerbositytrueStringIn list { None,Minimal,Default,Full }
-
LuaDocumentationtrueTable - - - - - - - - - - - - - - - - - - - - - - - -
KeyOptionalTypeRestrictionsDocumentation
TypefalseStringIn list { text,html }
FilefalseString
-
PropertyDocumentationtrueTable - - - - - - - - - - - - - - - - - - - - - - - -
KeyOptionalTypeRestrictionsDocumentation
TypefalseStringIn list { text,html }
FilefalseString
-
ScriptLogtrueTable - - - - - - - - - - - - - - - - - - - - - - - -
KeyOptionalTypeRestrictionsDocumentation
TypefalseStringIn list { text }
FilefalseString
-
KeyboardShortcutstrueTable - - - - - - - - - - - - - - - - - - - - - - - -
KeyOptionalTypeRestrictionsDocumentation
TypefalseStringIn list { text,html }
FilefalseString
-
DocumentationtrueTable - - - - - - - - - - - - - - - - - - - - - - - -
KeyOptionalTypeRestrictionsDocumentation
TypefalseStringIn list { text,html }
FilefalseString
-
ShutdownCountdowntrueDoubleGreater or equal to: 0.000000
DownloadRequestURLtrueString or Table or
RenderingMethodtrueStringIn list { Framebuffer,ABuffer }
DisableRenderingOnMastertrueBoolean
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Scene Description
KeyOptionalTypeRestrictionsDocumentation
ScenePathtrueString
CommonFoldertrueStringA valid scene module folder
CameratrueTable - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KeyOptionalTypeRestrictionsDocumentation
FocusfalseStringA valid object in the scene
PositiontrueVector3
RotationtrueVector4
-
ModulesfalseTable - - - - - - - - - - - - - - - - - - -
KeyOptionalTypeRestrictionsDocumentation
*falseStringLoadable module folders. This means that they either have to point to a folder that contains a ModuleFile or a folder which contains other folders that eventually contain ModuleFile. This second recursive approach is useful for grouping modules into logical units.
-
- - - - - - - - - - - - - - - - - - - -
Static Scaling
KeyOptionalTypeRestrictionsDocumentation
ScalefalseDouble
- - From a25a9b4a2d38346294e9d48fede8906dfbd6f713 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Fri, 16 Sep 2016 17:37:02 +0200 Subject: [PATCH 81/92] Add the ability to the FactoryManager to write documentation about all registered classes Enable this feature on default in openspace.cfg Move all generated documentations into a documentation folder Adapt gitignore accordingly --- .gitignore | 12 +-- .../openspace/engine/configurationmanager.h | 2 + include/openspace/util/factorymanager.h | 20 +++- include/openspace/util/factorymanager.inl | 4 +- modules/base/basemodule.cpp | 25 ++++- modules/newhorizons/newhorizonsmodule.cpp | 5 +- openspace.cfg | 17 ++-- src/engine/configurationmanager.cpp | 1 + src/engine/configurationmanager_doc.inl | 23 +++++ src/engine/openspaceengine.cpp | 20 +++- src/util/factorymanager.cpp | 91 ++++++++++++++++++- 11 files changed, 190 insertions(+), 30 deletions(-) diff --git a/.gitignore b/.gitignore index 9ec2a23d14..82afb83024 100644 --- a/.gitignore +++ b/.gitignore @@ -30,14 +30,9 @@ install_manifest.txt .project # Doxygen stuff -html/ -latex/ shaders/ABuffer/constants.hglsl *.OpenSpaceGenerated.glsl -LuaScripting.txt -Properties.txt log.html -Documentation.html data/scene/rosetta/67P/obj/67P_rotated_5_130.obj data/spice/NewHorizonsKernels/ data/scene/newhorizons/pluto/pluto/textures/ @@ -111,14 +106,11 @@ data/scene/juno/juno/textures data/scene/juno/juno/spice data/scene/juno/juno/Juno.mtl data/scene/juno/juno/Juno.obj -KeyboardMapping.txt saturn_rings.png data/scene/debugglobe/textures/ data/scene/rosetta/rosetta/obj/Rosetta.obj data/scene/rosetta/rosetta/rosetta/ data/scene/rosetta/rosetta/textures/ data/spice/Rosetta/ -KeyboardMapping.html -LuaScripting.html -Properties.html -Documentation.txt +documentation/ +doc/ diff --git a/include/openspace/engine/configurationmanager.h b/include/openspace/engine/configurationmanager.h index be33b3fafd..f242c6440f 100644 --- a/include/openspace/engine/configurationmanager.h +++ b/include/openspace/engine/configurationmanager.h @@ -65,6 +65,8 @@ public: static const std::string KeyKeyboardShortcuts; /// The key that stores the main documentation static const std::string KeyDocumentation; + /// The key that stores the factory documentation values + static const std::string KeyFactoryDocumentation; /// The key that stores the location of the scene file that is initially loaded static const std::string KeyConfigScene; /// The key that stores the subdirectory containing a list of all startup scripts to diff --git a/include/openspace/util/factorymanager.h b/include/openspace/util/factorymanager.h index 04903eb82b..acee69b919 100644 --- a/include/openspace/util/factorymanager.h +++ b/include/openspace/util/factorymanager.h @@ -86,9 +86,11 @@ public: /** * Adds the passed \p factory to the FactoryManager. Factories may only be added once. * \param factory The ghoul::TemplateFactory to add to this FactoryManager + * \param name A user-readable name for the registered factory. * \pre \p factory must not be nullptr */ - void addFactory(std::unique_ptr factory); + void addFactory(std::unique_ptr factory, + std::string name = ""); /** * This method provides access to all registered ghoul::TemplateFactory%s through @@ -102,11 +104,25 @@ public: template ghoul::TemplateFactory* factory() const; + /** + * Writes a documentation for the FactoryMananger that contains all of the registered + * factories and for each factory all registered class names. + * \param file The file to which the documentation will be written + * \param type The type of documentation that will be written + * \pre \p file must not be empty + * \pre \p type must not be empty + */ + void writeDocumentation(const std::string& file, const std::string& type); + private: /// Singleton member for the Factory Manager static FactoryManager* _manager; - std::vector> _factories; + struct FactoryInfo { + std::unique_ptr factory; + std::string name; + }; + std::vector _factories; }; } // namespace openspace diff --git a/include/openspace/util/factorymanager.inl b/include/openspace/util/factorymanager.inl index 7f9989f619..dde01bcef5 100644 --- a/include/openspace/util/factorymanager.inl +++ b/include/openspace/util/factorymanager.inl @@ -27,8 +27,8 @@ namespace openspace { template ghoul::TemplateFactory* FactoryManager::factory() const { for (auto& factory : _factories) { - if (factory->baseClassType() == typeid(T)) - return dynamic_cast*>(factory.get()); + if (factory.factory->baseClassType() == typeid(T)) + return dynamic_cast*>(factory.factory.get()); } throw FactoryNotFoundError(typeid(T).name()); diff --git a/modules/base/basemodule.cpp b/modules/base/basemodule.cpp index fb5731ec9f..8694b42b35 100644 --- a/modules/base/basemodule.cpp +++ b/modules/base/basemodule.cpp @@ -65,12 +65,27 @@ BaseModule::BaseModule() {} void BaseModule::internalInitialize() { - FactoryManager::ref().addFactory(std::make_unique>()); - FactoryManager::ref().addFactory(std::make_unique>()); - FactoryManager::ref().addFactory(std::make_unique>()); + FactoryManager::ref().addFactory( + std::make_unique>(), + "PlanetGeometry" + ); + FactoryManager::ref().addFactory( + std::make_unique>(), + "ModelGeometry" + ); + FactoryManager::ref().addFactory( + std::make_unique>(), + "ScreenSpaceRenderable" + ); - FactoryManager::ref().addFactory(std::make_unique>()); - FactoryManager::ref().addFactory(std::make_unique>()); + FactoryManager::ref().addFactory( + std::make_unique>(), + "Rotation" + ); + FactoryManager::ref().addFactory( + std::make_unique>(), + "Scale" + ); auto fScreenSpaceRenderable = FactoryManager::ref().factory(); ghoul_assert(fScreenSpaceRenderable, "ScreenSpaceRenderable factory was not created"); diff --git a/modules/newhorizons/newhorizonsmodule.cpp b/modules/newhorizons/newhorizonsmodule.cpp index 479afd7e5b..72caa9b844 100644 --- a/modules/newhorizons/newhorizonsmodule.cpp +++ b/modules/newhorizons/newhorizonsmodule.cpp @@ -51,7 +51,10 @@ NewHorizonsModule::NewHorizonsModule() void NewHorizonsModule::internalInitialize() { ImageSequencer::initialize(); - FactoryManager::ref().addFactory(std::make_unique>()); + FactoryManager::ref().addFactory( + std::make_unique>(), + "Decoder" + ); auto fRenderable = FactoryManager::ref().factory(); ghoul_assert(fRenderable, "No renderable factory existed"); diff --git a/openspace.cfg b/openspace.cfg index 26d17c9762..8ad6224f34 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -27,6 +27,7 @@ return { CONFIG = "${BASE_PATH}/config", CACHE = "${BASE_PATH}/cache", FONTS = "${OPENSPACE_DATA}/fonts", + DOCUMENTATION = "${BASE_PATH}/documentation" }, Fonts = { Mono = "${FONTS}/Droid_Sans_Mono/DroidSansMono.ttf", @@ -42,26 +43,30 @@ return { }, LuaDocumentation = { Type = "html", - File = "${BASE_PATH}/LuaScripting.html" + File = "${DOCUMENTATION}/LuaScripting.html" }, PropertyDocumentation = { Type = "html", - File = "${BASE_PATH}/Properties.html" + File = "${DOCUMENTATION}/Properties.html" }, ScriptLog = { Type = "text", - File = "${BASE_PATH}/ScriptLog.txt" + File = "${DOCUMENTATION}/ScriptLog.txt" }, KeyboardShortcuts = { Type = "html", - File = "${BASE_PATH}/KeyboardMapping.html" + File = "${DOCUMENTATION}/KeyboardMapping.html" }, Documentation = { Type = "html", - File = "${BASE_PATH}/Documentation.html" + File = "${DOCUMENTATION}/Documentation.html" + }, + FactoryDocumentation = { + Type = "html", + File = "${DOCUMENTATION}/FactoryDocumentation.html" }, ShutdownCountdown = 3, - DownloadRequestURL = "http://130.236.132.168/request.cgi", + DownloadRequestURL = "http://data.openspaceproject.com/request.cgi", RenderingMethod = "Framebuffer" --RenderingMethod = "ABuffer" -- alternative: "Framebuffer" diff --git a/src/engine/configurationmanager.cpp b/src/engine/configurationmanager.cpp index 5f737a39db..fb0972d471 100644 --- a/src/engine/configurationmanager.cpp +++ b/src/engine/configurationmanager.cpp @@ -54,6 +54,7 @@ const string ConfigurationManager::KeyScriptLog = "ScriptLog"; const string ConfigurationManager::KeyPropertyDocumentation = "PropertyDocumentation"; const string ConfigurationManager::KeyKeyboardShortcuts = "KeyboardShortcuts"; const string ConfigurationManager::KeyDocumentation = "Documentation"; +const string ConfigurationManager::KeyFactoryDocumentation = "FactoryDocumentation"; const string ConfigurationManager::KeyConfigScene = "Scene"; const string ConfigurationManager::KeyLogging = "Logging"; diff --git a/src/engine/configurationmanager_doc.inl b/src/engine/configurationmanager_doc.inl index 7ec2264f54..e83cda2239 100644 --- a/src/engine/configurationmanager_doc.inl +++ b/src/engine/configurationmanager_doc.inl @@ -263,6 +263,29 @@ Documentation ConfigurationManager::Documentation() { "This defines the location and type of this documentation file.", Optional::Yes }, + { + ConfigurationManager::KeyFactoryDocumentation, + new TableVerifier({ + { + ConfigurationManager::PartType, + new StringInListVerifier( + // List from FactoryManager::writeDocumentation + { "text", "html" } + ), + "The type of documentation that should be written." + }, + { + ConfigurationManager::PartFile, + new StringVerifier, + "The file that will be created on startup containing the factory " + "documentation. Any previous file in this location will be silently " + "overritten." + } + }), + "This defines the location and type of the factory documentation file, which " + "shows the different types of objects that can be created in the current " + "application configuration." + }, { ConfigurationManager::KeyShutdownCountdown, new DoubleGreaterEqualVerifier(0.0), diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index c9d88a5f74..7eea732086 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -152,10 +152,12 @@ OpenSpaceEngine::OpenSpaceEngine(std::string programName, FactoryManager::initialize(); FactoryManager::ref().addFactory( - std::make_unique>() + std::make_unique>(), + "Renderable" ); FactoryManager::ref().addFactory( - std::make_unique>() + std::make_unique>(), + "Ephemeris" ); SpiceManager::initialize(); Time::initialize(); @@ -445,6 +447,20 @@ bool OpenSpaceEngine::initialize() { _documentationEngine->writeDocumentation(documentationFile, documentationType); } + const std::string FactoryDocumentationType = + ConfigurationManager::KeyFactoryDocumentation + '.' + ConfigurationManager::PartType; + + const std::string FactoryDocumentationFile = + ConfigurationManager::KeyFactoryDocumentation + '.' + ConfigurationManager::PartFile; + bool hasFactoryDocumentationType = configurationManager().hasKey(FactoryDocumentationType); + bool hasFactoryDocumentationFile = configurationManager().hasKey(FactoryDocumentationFile); + if (hasFactoryDocumentationType && hasFactoryDocumentationFile) { + std::string type = configurationManager().value(FactoryDocumentationType); + std::string file = configurationManager().value(FactoryDocumentationFile); + + FactoryManager::ref().writeDocumentation(absPath(file), type); + } + bool disableMasterRendering = false; configurationManager().getValue( ConfigurationManager::KeyDisableMasterRendering, disableMasterRendering); diff --git a/src/util/factorymanager.cpp b/src/util/factorymanager.cpp index 5af4dab379..dd0f60cdce 100644 --- a/src/util/factorymanager.cpp +++ b/src/util/factorymanager.cpp @@ -26,6 +26,8 @@ #include +#include + namespace openspace { FactoryManager* FactoryManager::_manager = nullptr; @@ -57,9 +59,94 @@ FactoryManager& FactoryManager::ref() { return *_manager; } -void FactoryManager::addFactory(std::unique_ptr factory) { +void FactoryManager::addFactory(std::unique_ptr factory, + std::string name +) { ghoul_assert(factory, "Factory must not be nullptr"); - _factories.push_back(std::move(factory)); + _factories.push_back({ std::move(factory), std::move(name) }); +} + +void FactoryManager::writeDocumentation(const std::string& file, const std::string& type) { + if (type == "text") { + std::ofstream f; + f.exceptions(~std::ofstream::goodbit); + f.open(file); + + for (const FactoryInfo& factoryInfo : _factories) { + f << factoryInfo.name << '\n'; + + ghoul::TemplateFactoryBase* factory = factoryInfo.factory.get(); + for (const std::string& c : factory->registeredClasses()) { + f << '\t' << c << '\n'; + } + f << "\n\n"; + } + + } + else if (type == "html") { + +#ifdef JSON + std::stringstream json; + + json << "["; + for (const FactoryInfo& factoryInfo : _factories) { + json << "{"; + json << "\"name\": \"" << factoryInfo.name << "\","; + json << "\"classes\": ["; + + ghoul::TemplateFactoryBase* factory = factoryInfo.factory.get(); + for (const std::string& c : factory->registeredClasses()) { + json << "\"" << c << "\","; + } + + json << "]},"; + } + + json << "]"; + + // I did not check the output of this for correctness ---abock + std::string jsonText = json.str(); +#else + std::ofstream f; + f.exceptions(~std::ofstream::goodbit); + f.open(file); + + std::stringstream html; + html << "\n" + << "\t\n" + << "\t\tFactories\n" + << "\t\n" + << "\n" + << "\n" + << "\t\n\n" + << "\t\n" + << "\t\t\n" + << "\t\t\t\n" + << "\t\t\t\n" + << "\t\t\n" + << "\t\n" + << "\t\n"; + + for (const FactoryInfo& factoryInfo : _factories) { + html << "\t\t\n" + << "\t\t\t\n"; + + ghoul::TemplateFactoryBase* factory = factoryInfo.factory.get(); + for (const std::string& c : factory->registeredClasses()) { + html << "\t\t\t\n"; + } + html << "\t\n"; + + } + + html << "\t\n" + << "
Factories
TypeObject
" << factoryInfo.name << "
" << c << "
\n" + << ";"; + + f << html.str(); +#endif + + } } } // namespace openspace From 57701fb5a635023960a258fbc8df9a70f582b0f6 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Sun, 18 Sep 2016 15:13:34 +0200 Subject: [PATCH 82/92] Adding information to the Result that specifies the offending reason in addition to the offending key --- .../openspace/documentation/documentation.h | 16 +- include/openspace/documentation/verifier.h | 109 +++--- include/openspace/documentation/verifier.inl | 181 +++++----- src/documentation/documentation.cpp | 24 +- src/documentation/verifier.cpp | 102 +++--- tests/test_documentation.inl | 328 ++++++++++++------ 6 files changed, 440 insertions(+), 320 deletions(-) diff --git a/include/openspace/documentation/documentation.h b/include/openspace/documentation/documentation.h index 91f37c0648..10e00ad2a0 100644 --- a/include/openspace/documentation/documentation.h +++ b/include/openspace/documentation/documentation.h @@ -36,14 +36,22 @@ namespace openspace { namespace documentation { -struct Verifier; - using Optional = ghoul::Boolean; using Exhaustive = ghoul::Boolean; struct TestResult { + struct Offence { + enum class Reason { + MissingKey, + ExtraKey, + WrongType, + Verification + }; + std::string offender; + Reason reason; + }; bool success; - std::vector offenders; + std::vector offenders; }; struct SpecificationError : public ghoul::RuntimeError { @@ -52,6 +60,8 @@ struct SpecificationError : public ghoul::RuntimeError { TestResult result; }; +struct Verifier; + struct DocumentationEntry { DocumentationEntry(std::string key, Verifier* t, std::string doc = "", Optional optional = Optional::No); diff --git a/include/openspace/documentation/verifier.h b/include/openspace/documentation/verifier.h index cd37530e22..4152f76135 100644 --- a/include/openspace/documentation/verifier.h +++ b/include/openspace/documentation/verifier.h @@ -27,14 +27,14 @@ #include +#include + namespace openspace { namespace documentation { struct Verifier { - virtual TestResult operator()(const ghoul::Dictionary& dict, - const std::string& key) const; - - virtual bool test(const ghoul::Dictionary& dict, const std::string& key) const; + virtual TestResult operator()(const ghoul::Dictionary& dict, + const std::string& key) const = 0; virtual std::string type() const = 0; virtual std::string documentation() const; @@ -44,36 +44,36 @@ struct Verifier { template struct TemplateVerifier : public Verifier { using Type = T; + + TestResult operator()(const ghoul::Dictionary& dict, + const std::string& key) const override; }; struct BoolVerifier : public TemplateVerifier { - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string type() const override; }; struct DoubleVerifier : public TemplateVerifier { - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string type() const override; }; struct IntVerifier : public TemplateVerifier { - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + TestResult operator()(const ghoul::Dictionary& dict, + const std::string& key) const override; std::string type() const override; }; struct StringVerifier : public TemplateVerifier { - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string type() const override; }; struct TableVerifier : public TemplateVerifier { - TableVerifier(std::vector d = {}, Exhaustive exhaustive = Exhaustive::No); + TableVerifier(std::vector d = {}, + Exhaustive exhaustive = Exhaustive::No); - TestResult operator()(const ghoul::Dictionary& dict, const std::string& key) const override; + TestResult operator()(const ghoul::Dictionary& dict, + const std::string& key) const override; std::string type() const override; @@ -85,115 +85,94 @@ struct VectorVerifier {}; template struct Vector2Verifier : public TemplateVerifier>, public VectorVerifier { - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string type() const override; }; template struct Vector3Verifier : public TemplateVerifier>, public VectorVerifier { - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string type() const override; }; template struct Vector4Verifier : public TemplateVerifier>, public VectorVerifier { - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string type() const override; }; // Operator Verifiers +template +struct OperatorVerifier : public T { + OperatorVerifier(typename T::Type value); + + TestResult operator()(const ghoul::Dictionary& dict, + const std::string& key) const override; + + typename T::Type value; +}; template -struct LessVerifier : public T { +struct LessVerifier : public OperatorVerifier> { static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); static_assert(!std::is_base_of_v, "T cannot be VectorVerifier"); - LessVerifier(typename T::Type value); - - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + using OperatorVerifier::OperatorVerifier; std::string documentation() const; - - typename T::Type value; }; template -struct LessEqualVerifier : public T { +struct LessEqualVerifier : public OperatorVerifier> { static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); static_assert(!std::is_base_of_v, "T cannot be VectorVerifier"); - LessEqualVerifier(typename T::Type value); - - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + using OperatorVerifier::OperatorVerifier; std::string documentation() const override; - - typename T::Type value; }; template -struct GreaterVerifier : public T { +struct GreaterVerifier : public OperatorVerifier> { static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); static_assert(!std::is_base_of_v, "T cannot be VectorVerifier"); - GreaterVerifier(typename T::Type value); - - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + using OperatorVerifier::OperatorVerifier; std::string documentation() const override; - - typename T::Type value; }; template -struct GreaterEqualVerifier : public T { +struct GreaterEqualVerifier : public OperatorVerifier> { static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); static_assert(!std::is_base_of_v, "T cannot be StringVerifier"); static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); static_assert(!std::is_base_of_v, "T cannot be VectorVerifier"); - GreaterEqualVerifier(typename T::Type value); - - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + using OperatorVerifier::OperatorVerifier; std::string documentation() const override; - - typename T::Type value; }; template -struct EqualVerifier : public T { +struct EqualVerifier : public OperatorVerifier> { static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); - EqualVerifier(typename T::Type value); - - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + using OperatorVerifier::OperatorVerifier; std::string documentation() const override; - - typename T::Type value; }; template -struct UnequalVerifier : public T { +struct UnequalVerifier : public OperatorVerifier> { static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); - UnequalVerifier(typename T::Type value); - - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + using OperatorVerifier::OperatorVerifier; std::string documentation() const override; - - typename T::Type value; }; // List Verifiers @@ -204,7 +183,8 @@ struct InListVerifier : public T { InListVerifier(std::vector values); - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + TestResult operator()(const ghoul::Dictionary& dict, + const std::string& key) const override; std::string documentation() const override; @@ -217,7 +197,8 @@ struct NotInListVerifier : public T { NotInListVerifier(std::vector values); - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + TestResult operator()(const ghoul::Dictionary& dict, + const std::string& key) const override; std::string documentation() const override; @@ -234,7 +215,8 @@ struct InRangeVerifier : public T { InRangeVerifier(typename T::Type lower, typename T::Type upper); - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + TestResult operator()(const ghoul::Dictionary& dict, + const std::string& key) const override; std::string documentation() const override; @@ -251,7 +233,8 @@ struct NotInRangeVerifier : public T { NotInRangeVerifier(typename T::Type lower, typename T::Type upper); - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + TestResult operator()(const ghoul::Dictionary& dict, + const std::string& key) const override; std::string documentation() const override; @@ -265,8 +248,6 @@ template struct AnnotationVerifier : public T { AnnotationVerifier(std::string annotation); - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string documentation() const override; std::string annotation; @@ -277,7 +258,8 @@ struct AnnotationVerifier : public T { struct AndVerifier : public Verifier { AndVerifier(Verifier* a, Verifier* b); - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + TestResult operator()(const ghoul::Dictionary& dict, + const std::string& key) const override; std::string type() const override; std::string documentation() const override; @@ -289,7 +271,8 @@ struct AndVerifier : public Verifier { struct OrVerifier : public Verifier { OrVerifier(Verifier* a, Verifier* b); - bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + TestResult operator()(const ghoul::Dictionary& dict, + const std::string& key) const override; std::string type() const override; std::string documentation() const override; diff --git a/include/openspace/documentation/verifier.inl b/include/openspace/documentation/verifier.inl index bfc155dae8..2e0891489d 100644 --- a/include/openspace/documentation/verifier.inl +++ b/include/openspace/documentation/verifier.inl @@ -32,8 +32,20 @@ namespace openspace { namespace documentation { template -bool Vector2Verifier::test(const ghoul::Dictionary& d, const std::string& k) const { - return d.hasKeyAndValue>(k); +TestResult TemplateVerifier::operator()(const ghoul::Dictionary& dict, + const std::string& key) const +{ + if (dict.hasKey(key)) { + if (dict.hasValue(key)) { + return{ true, {} }; + } + else { + return { false, { { key, TestResult::Offence::Reason::WrongType } } }; + } + } + else { + return { false, { { key, TestResult::Offence::Reason::MissingKey } } }; + } } template @@ -43,11 +55,6 @@ std::string Vector2Verifier::type() const { return "Vector2<"s + typeid(T).name() + ">"; } -template -bool Vector3Verifier::test(const ghoul::Dictionary& d, const std::string& k) const { - return d.hasKeyAndValue>(k); -} - template std::string Vector3Verifier::type() const { using namespace std::string_literals; @@ -55,11 +62,6 @@ std::string Vector3Verifier::type() const { return "Vector3<"s + typeid(T).name() + ">"; } -template -bool Vector4Verifier::test(const ghoul::Dictionary& d, const std::string& k) const { - return d.hasKeyAndValue>(k); -} - template std::string Vector4Verifier::type() const { using namespace std::string_literals; @@ -67,15 +69,27 @@ std::string Vector4Verifier::type() const { return "Vector4<"s + typeid(T).name() + ">"; } -template -LessVerifier::LessVerifier(typename T::Type value) +template +OperatorVerifier::OperatorVerifier(typename T::Type value) : value(std::move(value)) -{ -} +{} -template -bool LessVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { - return T::test(dict, key) && dict.value(key) < value; +template +TestResult OperatorVerifier::operator()(const ghoul::Dictionary& dict, + const std::string& key) const +{ + TestResult res = T::operator()(dict, key); + if (res.success) { + if (Op()(dict.value(key), value)) { + return { true, {} }; + } + else { + return { false, { { key, TestResult::Offence::Reason::Verification }}}; + } + } + else { + return res; + } } template @@ -83,77 +97,26 @@ std::string LessVerifier::documentation() const { return "Less than: " + std::to_string(value); } - -template -LessEqualVerifier::LessEqualVerifier(typename T::Type value) - : value(std::move(value)) -{} - -template -bool LessEqualVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { - return T::test(dict, key) && dict.value(key) <= value; -} - template std::string LessEqualVerifier::documentation() const { return "Less or equal to: " + std::to_string(value); } -template -GreaterVerifier::GreaterVerifier(typename T::Type value) - : value(std::move(value)) -{} - -template -bool GreaterVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { - return T::test(dict, key) && dict.value(key) > value; -} - template std::string GreaterVerifier::documentation() const { return "Greater than: " + std::to_string(value); } -template -GreaterEqualVerifier::GreaterEqualVerifier(typename T::Type value) - : value(std::move(value)) -{} - -template -bool GreaterEqualVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { - return T::test(dict, key) && dict.value(key) >= value; -} - template std::string GreaterEqualVerifier::documentation() const { return "Greater or equal to: " + std::to_string(value); } -template -EqualVerifier::EqualVerifier(typename T::Type value) - : value(std::move(value)) -{} - -template -bool EqualVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { - return T::test(dict, key) && dict.value(key) == value; -} - template std::string EqualVerifier::documentation() const { return "Equal to: " + std::to_string(value); } -template -UnequalVerifier::UnequalVerifier(typename T::Type value) - : value(std::move(value)) -{} - -template -bool UnequalVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { - return T::test(dict, key) && dict.value(key) != value; -} - template std::string UnequalVerifier::documentation() const { return "Unequal to: " + std::to_string(value); @@ -165,15 +128,24 @@ InListVerifier::InListVerifier(std::vector values) {} template -bool InListVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { - if (T::test(dict, key)) { +TestResult InListVerifier::operator()(const ghoul::Dictionary& dict, + const std::string& key) const +{ + TestResult res = T::operator()(dict, key); + if (res.success) { typename T::Type value = dict.value(key); auto it = std::find(values.begin(), values.end(), value); - return it != values.end(); + + if (it != values.end()) { + return { true, {} }; + } + else { + return { false, { { key, TestResult::Offence::Reason::Verification } } }; + } } else { - return false; + return res; } } @@ -198,15 +170,24 @@ NotInListVerifier::NotInListVerifier(std::vector values) {} template -bool NotInListVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { - if (T::test(dict, key)) { +TestResult NotInListVerifier::operator()(const ghoul::Dictionary& dict, + const std::string& key) const +{ + TestResult res = T::operator()(dict, key); + if (res.success) { typename T::Type value = dict.value(key); auto it = std::find(values.begin(), values.end(), value); - return it == values.end(); + + if (it == values.end()) { + return { true, {} }; + } + else { + return { false, { { key, TestResult::Offence::Reason::Verification } } }; + } } else { - return false; + return res; } } @@ -234,14 +215,24 @@ InRangeVerifier::InRangeVerifier(typename T::Type lower, typename T::Type upp ghoul_assert(lower <= upper, "Lower value must be smaller or equal to upper value"); } + template -bool InRangeVerifier::test(const ghoul::Dictionary& d, const std::string& key) const { - if (T::test(d, key)) { - typename T::Type val = d.value(key); - return val >= lower && val <= upper; +TestResult InRangeVerifier::operator()(const ghoul::Dictionary& dict, + const std::string& key) const +{ + TestResult res = T::operator()(dict, key); + if (res.success) { + typename T::Type val = dict.value(key); + + if (val >= lower && val <= upper) { + return { true, {} }; + } + else { + return { false, { { key, TestResult::Offence::Reason::Verification } } }; + } } else { - return false; + return res; } } @@ -260,13 +251,21 @@ NotInRangeVerifier::NotInRangeVerifier(typename T::Type lower, typename T::Ty } template -bool NotInRangeVerifier::test(const ghoul::Dictionary& d, const std::string& k) const { - if (T::test(d, k)) { - typename T::Type val = d.value(k); - return !(val >= lower && val <= upper); +TestResult NotInRangeVerifier::operator()(const ghoul::Dictionary& dict, + const std::string& key) const { + TestResult res = T::operator()(dict, key); + if (res.success) { + typename T::Type val = dict.value(key); + + if (val >= lower && val <= upper) { + return { false, { { key, TestResult::Offence::Reason::Verification } } }; + } + else { + return { true, {} }; + } } else { - return false; + return res; } } @@ -282,12 +281,6 @@ AnnotationVerifier::AnnotationVerifier(std::string annotation) : annotation(std::move(annotation)) {} -template -bool AnnotationVerifier::test(const ghoul::Dictionary& dict, - const std::string& key) const -{ - return T::test(dict, key); -} template std::string AnnotationVerifier::documentation() const { diff --git a/src/documentation/documentation.cpp b/src/documentation/documentation.cpp index b908c5d551..6a1fd379fa 100644 --- a/src/documentation/documentation.cpp +++ b/src/documentation/documentation.cpp @@ -29,6 +29,22 @@ namespace { const std::string Wildcard = "*"; + + // Structure used to make offences unique + struct OffenceCompare { + using Offence = openspace::documentation::TestResult::Offence; + bool operator()(const Offence& lhs, const Offence& rhs) const + { + if (lhs.offender != rhs.offender) { + return lhs.offender < rhs.offender; + } + else { + return std::underlying_type_t(lhs.reason) < + std::underlying_type_t(rhs.reason); + } + } + + }; } // namespace namespace std { @@ -119,17 +135,19 @@ TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& di if (it == d.entries.end()) { result.success = false; - result.offenders.push_back(key); + result.offenders.push_back( + { key, TestResult::Offence::Reason::ExtraKey } + ); } } } // Remove duplicate offenders that might occur if multiple rules apply to a single // key and more than one of these rules are broken - std::set uniqueOffenders( + std::set uniqueOffenders( result.offenders.begin(), result.offenders.end() ); - result.offenders = std::vector( + result.offenders = std::vector( uniqueOffenders.begin(), uniqueOffenders.end() ); diff --git a/src/documentation/verifier.cpp b/src/documentation/verifier.cpp index c1db34e868..af51e33c51 100644 --- a/src/documentation/verifier.cpp +++ b/src/documentation/verifier.cpp @@ -74,56 +74,45 @@ template struct AnnotationVerifier; template struct AnnotationVerifier; template struct AnnotationVerifier; -TestResult Verifier::operator()(const ghoul::Dictionary& dict, - const std::string& key) const -{ - bool testSuccess = test(dict, key); - if (testSuccess) { - return { testSuccess,{} }; - } - else { - return { testSuccess,{ key } }; - } -} - -bool Verifier::test(const ghoul::Dictionary& dict, const std::string& key) const { - return false; -}; - std::string Verifier::documentation() const { return ""; } -bool BoolVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { - return dict.hasKeyAndValue(key); -} - std::string BoolVerifier::type() const { return "Boolean"; } -bool DoubleVerifier::test(const ghoul::Dictionary & dict, const std::string & key) const { - return dict.hasKeyAndValue(key); -} - std::string DoubleVerifier::type() const { return "Double"; } -bool IntVerifier::test(const ghoul::Dictionary & dict, const std::string & key) const { +TestResult IntVerifier::operator()(const ghoul::Dictionary & dict, + const std::string & key) const +{ if (dict.hasKeyAndValue(key)) { - return true; + return { true, {} }; } else { - if (dict.hasKeyAndValue(key)) { - // If we have a double value, we need to check if it is integer - double value = dict.value(key); - double intPart; - return modf(value, &intPart) == 0.0; + if (dict.hasKey(key)) { + if (dict.hasValue(key)) { + // If we have a double value, we need to check if it is integer + double value = dict.value(key); + double intPart; + bool isInt = modf(value, &intPart) == 0.0; + if (isInt) { + return { true,{} }; + } + else { + return { false, { { key, TestResult::Offence::Reason::WrongType } } }; + } + } + else { + // If we don't have a double value, we cannot have an int value + return { false, { { key, TestResult::Offence::Reason::WrongType } } }; + } } else { - // If we don't have a double value, we cannot have an int value - return false; + return { false, { {key, TestResult::Offence::Reason::MissingKey }}}; } } } @@ -132,10 +121,6 @@ std::string IntVerifier::type() const { return "Integer"; } -bool StringVerifier::test(const ghoul::Dictionary & dict, const std::string & key) const { - return dict.hasKeyAndValue(key); -} - std::string StringVerifier::type() const { return "String"; } @@ -149,16 +134,24 @@ TestResult TableVerifier::operator()(const ghoul::Dictionary& dict, const std::string& key) const { if (dict.hasKeyAndValue(key)) { - ghoul::Dictionary d = dict.value(key); + ghoul::Dictionary d = dict.value(key); TestResult res = testSpecification({ "", doc, exhaustive }, d); - for (std::string& s : res.offenders) { - s = key + "." + s; + for (TestResult::Offence& s : res.offenders) { + s.offender = key + "." + s.offender; } return res; } - return { dict.hasKeyAndValue(key), { key } }; + else { + if (dict.hasKey(key)) { + return { false, { { key, TestResult::Offence::Reason::WrongType } } }; + + } + else { + return { false, { { key, TestResult::Offence::Reason::MissingKey } } }; + } + } } std::string TableVerifier::type() const { @@ -172,8 +165,18 @@ AndVerifier::AndVerifier(Verifier* a, Verifier* b) ghoul_assert(a->type() == b->type(), "Cannot use AndVerifier with different types"); } -bool AndVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { - return a->test(dict, key) && b->test(dict, key); +TestResult AndVerifier::operator()(const ghoul::Dictionary& dict, + const std::string& key) const +{ + TestResult resA = a->operator()(dict, key); + TestResult resB = b->operator()(dict, key); + + if (resA.success && resB.success) { + return { true, {} }; + } + else { + return { false, { { key, TestResult::Offence::Reason::Verification } } }; + } } std::string AndVerifier::type() const { @@ -190,8 +193,17 @@ OrVerifier::OrVerifier(Verifier* a, Verifier* b) , b(b) {} -bool OrVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { - return a->test(dict, key) || b->test(dict, key); +TestResult OrVerifier::operator()(const ghoul::Dictionary& dict, + const std::string& key) const { + TestResult resA = a->operator()(dict, key); + TestResult resB = b->operator()(dict, key); + + if (resA.success || resB.success) { + return { true, {} }; + } + else { + return { false, { { key, TestResult::Offence::Reason::Verification } } }; + } } std::string OrVerifier::type() const { diff --git a/tests/test_documentation.inl b/tests/test_documentation.inl index 34e8d05f6b..bff9c7dfb0 100644 --- a/tests/test_documentation.inl +++ b/tests/test_documentation.inl @@ -180,7 +180,8 @@ TEST_F(DocumentationTest, BoolVerifier) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Bool", negativeRes.offenders[0]); + EXPECT_EQ("Bool", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); ghoul::Dictionary negativeExist { { "Bool2", 0} @@ -189,7 +190,8 @@ TEST_F(DocumentationTest, BoolVerifier) { EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Bool", negativeRes.offenders[0]); + EXPECT_EQ("Bool", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::MissingKey, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, DoubleVerifier) { @@ -215,15 +217,17 @@ TEST_F(DocumentationTest, DoubleVerifier) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0]); + EXPECT_EQ("Double", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); ghoul::Dictionary negativeExist{ { "Double2" , 0.0 } }; - negativeRes = testSpecification(doc, negative); + negativeRes = testSpecification(doc, negativeExist); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0]); + EXPECT_EQ("Double", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::MissingKey, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, IntVerifier) { @@ -255,15 +259,17 @@ TEST_F(DocumentationTest, IntVerifier) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Int", negativeRes.offenders[0]); + EXPECT_EQ("Int", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); ghoul::Dictionary negativeExist { { "Int2", 0 } }; - negativeRes = testSpecification(doc, negative); + negativeRes = testSpecification(doc, negativeExist); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Int", negativeRes.offenders[0]); + EXPECT_EQ("Int", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::MissingKey, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, StringVerifier) { @@ -288,15 +294,17 @@ TEST_F(DocumentationTest, StringVerifier) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("String", negativeRes.offenders[0]); + EXPECT_EQ("String", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); ghoul::Dictionary negativeExist { { "String2", ""s } }; - negativeRes = testSpecification(doc, negative); + negativeRes = testSpecification(doc, negativeExist); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("String", negativeRes.offenders[0]); + EXPECT_EQ("String", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::MissingKey, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, TableVerifierType) { @@ -320,15 +328,17 @@ TEST_F(DocumentationTest, TableVerifierType) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Table", negativeRes.offenders[0]); + EXPECT_EQ("Table", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); ghoul::Dictionary negativeExist { { "Table2", ghoul::Dictionary{} } }; - negativeRes = testSpecification(doc, negative); + negativeRes = testSpecification(doc, negativeExist); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Table", negativeRes.offenders[0]); + EXPECT_EQ("Table", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::MissingKey, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, MixedVerifiers) { @@ -367,7 +377,8 @@ TEST_F(DocumentationTest, MixedVerifiers) { TestResult negativeRes = testSpecification(doc, negative1); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0]); + EXPECT_EQ("Double", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); ghoul::Dictionary negative2 { { "Bool", true }, @@ -379,8 +390,10 @@ TEST_F(DocumentationTest, MixedVerifiers) { negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(2, negativeRes.offenders.size()); - EXPECT_EQ("Int", negativeRes.offenders[0]); - EXPECT_EQ("String", negativeRes.offenders[1]); + EXPECT_EQ("Int", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + EXPECT_EQ("String", negativeRes.offenders[1].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[1].reason); } TEST_F(DocumentationTest, NestedTables) { @@ -440,7 +453,8 @@ TEST_F(DocumentationTest, NestedTables) { TestResult negativeRes = testSpecification(doc, negativeSimple); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Outer_Table", negativeRes.offenders[0]); + EXPECT_EQ("Outer_Table", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); ghoul::Dictionary negativeInner { { "Outer_Int", 1 }, @@ -460,7 +474,8 @@ TEST_F(DocumentationTest, NestedTables) { negativeRes = testSpecification(doc, negativeInner); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Outer_Table.Inner_Double", negativeRes.offenders[0]); + EXPECT_EQ("Outer_Table.Inner_Double", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); ghoul::Dictionary negativeInner2 { { "Outer_Int", 1 }, @@ -480,8 +495,10 @@ TEST_F(DocumentationTest, NestedTables) { negativeRes = testSpecification(doc, negativeInner2); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(2, negativeRes.offenders.size()); - EXPECT_EQ("Outer_Table.Inner_Double", negativeRes.offenders[0]); - EXPECT_EQ("Outer_Table.Inner_String", negativeRes.offenders[1]); + EXPECT_EQ("Outer_Table.Inner_Double", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + EXPECT_EQ("Outer_Table.Inner_String", negativeRes.offenders[1].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[1].reason); ghoul::Dictionary negativeInnerSeparate { { "Outer_Int", 1 }, @@ -501,8 +518,10 @@ TEST_F(DocumentationTest, NestedTables) { negativeRes = testSpecification(doc, negativeInnerSeparate); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(2, negativeRes.offenders.size()); - EXPECT_EQ("Outer_Table.Inner_Double", negativeRes.offenders[0]); - EXPECT_EQ("Outer_Table2.Inner_Double2", negativeRes.offenders[1]); + EXPECT_EQ("Outer_Table.Inner_Double", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + EXPECT_EQ("Outer_Table2.Inner_Double2", negativeRes.offenders[1].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[1].reason); ghoul::Dictionary negativeInnerFull { { "Outer_Int", 1 }, @@ -522,9 +541,12 @@ TEST_F(DocumentationTest, NestedTables) { negativeRes = testSpecification(doc, negativeInnerFull); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(3, negativeRes.offenders.size()); - EXPECT_EQ("Outer_Table.Inner_Double", negativeRes.offenders[0]); - EXPECT_EQ("Outer_Table2.Inner_Double2", negativeRes.offenders[1]); - EXPECT_EQ("Outer_Table2.Inner_Table.Inner_Inner_Int", negativeRes.offenders[2]); + EXPECT_EQ("Outer_Table.Inner_Double", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + EXPECT_EQ("Outer_Table2.Inner_Double2", negativeRes.offenders[1].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[1].reason); + EXPECT_EQ("Outer_Table2.Inner_Table.Inner_Inner_Int", negativeRes.offenders[2].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[2].reason); } TEST_F(DocumentationTest, Optional) { @@ -558,7 +580,8 @@ TEST_F(DocumentationTest, Optional) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Bool_Force", negativeRes.offenders[0]); + EXPECT_EQ("Bool_Force", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::MissingKey, negativeRes.offenders[0].reason); ghoul::Dictionary negative2 { { "Bool_Optional", true } @@ -566,7 +589,8 @@ TEST_F(DocumentationTest, Optional) { negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Bool_Force", negativeRes.offenders[0]); + EXPECT_EQ("Bool_Force", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::MissingKey, negativeRes.offenders[0].reason); ghoul::Dictionary negative3 { { "Bool_Force", true }, @@ -575,7 +599,8 @@ TEST_F(DocumentationTest, Optional) { negativeRes = testSpecification(doc, negative3); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Bool_Optional", negativeRes.offenders[0]); + EXPECT_EQ("Bool_Optional", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, RequiredInOptional) { @@ -636,7 +661,8 @@ TEST_F(DocumentationTest, RequiredInOptional) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a.b", negativeRes.offenders[0]); + EXPECT_EQ("a.b", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::MissingKey, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, Exhaustive) { @@ -661,8 +687,10 @@ TEST_F(DocumentationTest, Exhaustive) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(2, negativeRes.offenders.size()); - EXPECT_EQ("False_Int", negativeRes.offenders[0]); - EXPECT_EQ("Int", negativeRes.offenders[1]); + EXPECT_EQ("False_Int", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::ExtraKey, negativeRes.offenders[0].reason); + EXPECT_EQ("Int", negativeRes.offenders[1].offender); + EXPECT_EQ(TestResult::Offence::Reason::MissingKey, negativeRes.offenders[1].reason); ghoul::Dictionary negative2 { { "Double", 2.0 } @@ -670,8 +698,10 @@ TEST_F(DocumentationTest, Exhaustive) { negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(2, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0]); - EXPECT_EQ("Int", negativeRes.offenders[1]); + EXPECT_EQ("Double", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::ExtraKey, negativeRes.offenders[0].reason); + EXPECT_EQ("Int", negativeRes.offenders[1].offender); + EXPECT_EQ(TestResult::Offence::Reason::MissingKey, negativeRes.offenders[1].reason); } TEST_F(DocumentationTest, NestedExhaustive) { @@ -699,8 +729,10 @@ TEST_F(DocumentationTest, NestedExhaustive) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(2, negativeRes.offenders.size()); - EXPECT_EQ("Table.a", negativeRes.offenders[0]); - EXPECT_EQ("Table.b", negativeRes.offenders[1]); + EXPECT_EQ("Table.a", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::MissingKey, negativeRes.offenders[0].reason); + EXPECT_EQ("Table.b", negativeRes.offenders[1].offender); + EXPECT_EQ(TestResult::Offence::Reason::ExtraKey, negativeRes.offenders[1].reason); } TEST_F(DocumentationTest, LessInt) { @@ -724,7 +756,8 @@ TEST_F(DocumentationTest, LessInt) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Int", negativeRes.offenders[0]); + EXPECT_EQ("Int", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, LessDouble) { @@ -748,7 +781,8 @@ TEST_F(DocumentationTest, LessDouble) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0]); + EXPECT_EQ("Double", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, LessEqualInt) { @@ -779,7 +813,8 @@ TEST_F(DocumentationTest, LessEqualInt) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Int", negativeRes.offenders[0]); + EXPECT_EQ("Int", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, LessEqualDouble) { @@ -810,7 +845,8 @@ TEST_F(DocumentationTest, LessEqualDouble) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0]); + EXPECT_EQ("Double", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, GreaterInt) { @@ -829,12 +865,13 @@ TEST_F(DocumentationTest, GreaterInt) { EXPECT_EQ(0, positiveRes.offenders.size()); ghoul::Dictionary negative { - { "Int", 00 } + { "Int", 0 } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Int", negativeRes.offenders[0]); + EXPECT_EQ("Int", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, GreaterDouble) { @@ -858,7 +895,8 @@ TEST_F(DocumentationTest, GreaterDouble) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0]); + EXPECT_EQ("Double", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, GreaterEqualInt) { @@ -889,7 +927,8 @@ TEST_F(DocumentationTest, GreaterEqualInt) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Int", negativeRes.offenders[0]); + EXPECT_EQ("Int", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, GreaterEqualDouble) { @@ -920,10 +959,10 @@ TEST_F(DocumentationTest, GreaterEqualDouble) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0]); + EXPECT_EQ("Double", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); } - TEST_F(DocumentationTest, EqualBool) { using namespace openspace::documentation; @@ -945,7 +984,8 @@ TEST_F(DocumentationTest, EqualBool) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Bool", negativeRes.offenders[0]); + EXPECT_EQ("Bool", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, EqualInt) { @@ -969,7 +1009,8 @@ TEST_F(DocumentationTest, EqualInt) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Int", negativeRes.offenders[0]); + EXPECT_EQ("Int", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, EqualDouble) { @@ -993,7 +1034,8 @@ TEST_F(DocumentationTest, EqualDouble) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0]); + EXPECT_EQ("Double", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, EqualString) { @@ -1018,7 +1060,8 @@ TEST_F(DocumentationTest, EqualString) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("String", negativeRes.offenders[0]); + EXPECT_EQ("String", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, UnequalBool) { @@ -1042,7 +1085,8 @@ TEST_F(DocumentationTest, UnequalBool) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Bool", negativeRes.offenders[0]); + EXPECT_EQ("Bool", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, UnequalInt) { @@ -1066,7 +1110,8 @@ TEST_F(DocumentationTest, UnequalInt) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Int", negativeRes.offenders[0]); + EXPECT_EQ("Int", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, UnequalDouble) { @@ -1090,7 +1135,8 @@ TEST_F(DocumentationTest, UnequalDouble) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0]); + EXPECT_EQ("Double", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, UnequalString) { @@ -1115,7 +1161,8 @@ TEST_F(DocumentationTest, UnequalString) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("String", negativeRes.offenders[0]); + EXPECT_EQ("String", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, ListBool) { @@ -1139,7 +1186,8 @@ TEST_F(DocumentationTest, ListBool) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Bool", negativeRes.offenders[0]); + EXPECT_EQ("Bool", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, ListInt) { @@ -1170,7 +1218,8 @@ TEST_F(DocumentationTest, ListInt) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Int", negativeRes.offenders[0]); + EXPECT_EQ("Int", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, ListDouble) { @@ -1201,7 +1250,8 @@ TEST_F(DocumentationTest, ListDouble) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0]); + EXPECT_EQ("Double", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, ListString) { @@ -1233,7 +1283,8 @@ TEST_F(DocumentationTest, ListString) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("String", negativeRes.offenders[0]); + EXPECT_EQ("String", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, NotListBool) { @@ -1257,7 +1308,8 @@ TEST_F(DocumentationTest, NotListBool) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Bool", negativeRes.offenders[0]); + EXPECT_EQ("Bool", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, NotListInt) { @@ -1288,7 +1340,8 @@ TEST_F(DocumentationTest, NotListInt) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Int", negativeRes.offenders[0]); + EXPECT_EQ("Int", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, NotListDouble) { @@ -1319,7 +1372,8 @@ TEST_F(DocumentationTest, NotListDouble) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0]); + EXPECT_EQ("Double", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, NotListString) { @@ -1351,7 +1405,8 @@ TEST_F(DocumentationTest, NotListString) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("String", negativeRes.offenders[0]); + EXPECT_EQ("String", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, AnnotationBool) { @@ -1375,7 +1430,8 @@ TEST_F(DocumentationTest, AnnotationBool) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Bool", negativeRes.offenders[0]); + EXPECT_EQ("Bool", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, AnnotationInt) { @@ -1399,7 +1455,8 @@ TEST_F(DocumentationTest, AnnotationInt) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Int", negativeRes.offenders[0]); + EXPECT_EQ("Int", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, AnnotationDouble) { @@ -1423,7 +1480,8 @@ TEST_F(DocumentationTest, AnnotationDouble) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0]); + EXPECT_EQ("Double", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, AnnotationString) { @@ -1448,7 +1506,8 @@ TEST_F(DocumentationTest, AnnotationString) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("String", negativeRes.offenders[0]); + EXPECT_EQ("String", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, AnnotationTable) { @@ -1472,7 +1531,8 @@ TEST_F(DocumentationTest, AnnotationTable) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Table", negativeRes.offenders[0]); + EXPECT_EQ("Table", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, InRangeInt) { @@ -1510,7 +1570,8 @@ TEST_F(DocumentationTest, InRangeInt) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Int", negativeRes.offenders[0]); + EXPECT_EQ("Int", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, InRangeDouble) { @@ -1555,7 +1616,8 @@ TEST_F(DocumentationTest, InRangeDouble) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0]); + EXPECT_EQ("Double", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, NotInRangeInt) { @@ -1586,7 +1648,8 @@ TEST_F(DocumentationTest, NotInRangeInt) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Int", negativeRes.offenders[0]); + EXPECT_EQ("Int", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); ghoul::Dictionary negative2 { { "Int", 0 } @@ -1594,7 +1657,8 @@ TEST_F(DocumentationTest, NotInRangeInt) { negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Int", negativeRes.offenders[0]); + EXPECT_EQ("Int", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); ghoul::Dictionary negative3 { { "Int", 5 } @@ -1602,7 +1666,8 @@ TEST_F(DocumentationTest, NotInRangeInt) { negativeRes = testSpecification(doc, negative3); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Int", negativeRes.offenders[0]); + EXPECT_EQ("Int", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, NotInRangeDouble) { @@ -1633,7 +1698,8 @@ TEST_F(DocumentationTest, NotInRangeDouble) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0]); + EXPECT_EQ("Double", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); ghoul::Dictionary negative2 { { "Double", 5.0 } @@ -1641,7 +1707,8 @@ TEST_F(DocumentationTest, NotInRangeDouble) { negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0]); + EXPECT_EQ("Double", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); ghoul::Dictionary negative3 { { "Double", 2.5 } @@ -1649,7 +1716,8 @@ TEST_F(DocumentationTest, NotInRangeDouble) { negativeRes = testSpecification(doc, negative3); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0]); + EXPECT_EQ("Double", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, Wildcard) { @@ -1677,7 +1745,8 @@ TEST_F(DocumentationTest, Wildcard) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0]); + EXPECT_EQ("a", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); ghoul::Dictionary negative2 { { "a", false }, @@ -1687,8 +1756,10 @@ TEST_F(DocumentationTest, Wildcard) { negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(2, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0]); - EXPECT_EQ("b", negativeRes.offenders[1]); + EXPECT_EQ("a", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + EXPECT_EQ("b", negativeRes.offenders[1].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[1].reason); ghoul::Dictionary negative3 { { "a", false }, @@ -1698,9 +1769,12 @@ TEST_F(DocumentationTest, Wildcard) { negativeRes = testSpecification(doc, negative3); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(3, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0]); - EXPECT_EQ("b", negativeRes.offenders[1]); - EXPECT_EQ("c", negativeRes.offenders[2]); + EXPECT_EQ("a", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + EXPECT_EQ("b", negativeRes.offenders[1].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[1].reason); + EXPECT_EQ("c", negativeRes.offenders[2].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[2].reason); } TEST_F(DocumentationTest, WildcardMixed) { @@ -1731,8 +1805,10 @@ TEST_F(DocumentationTest, WildcardMixed) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(2, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0]); - EXPECT_EQ("b", negativeRes.offenders[1]); + EXPECT_EQ("a", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + EXPECT_EQ("b", negativeRes.offenders[1].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[1].reason); ghoul::Dictionary negative2 { { "a", false }, @@ -1742,8 +1818,10 @@ TEST_F(DocumentationTest, WildcardMixed) { negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(2, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0]); - EXPECT_EQ("b", negativeRes.offenders[1]); + EXPECT_EQ("a", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + EXPECT_EQ("b", negativeRes.offenders[1].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[1].reason); ghoul::Dictionary negative3 { { "a", false }, @@ -1753,9 +1831,12 @@ TEST_F(DocumentationTest, WildcardMixed) { negativeRes = testSpecification(doc, negative3); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(3, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0]); - EXPECT_EQ("b", negativeRes.offenders[1]); - EXPECT_EQ("c", negativeRes.offenders[2]); + EXPECT_EQ("a", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + EXPECT_EQ("b", negativeRes.offenders[1].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[1].reason); + EXPECT_EQ("c", negativeRes.offenders[2].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[2].reason); ghoul::Dictionary negative4 { { "a", false }, @@ -1765,8 +1846,10 @@ TEST_F(DocumentationTest, WildcardMixed) { negativeRes = testSpecification(doc, negative4); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(2, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0]); - EXPECT_EQ("c", negativeRes.offenders[1]); + EXPECT_EQ("a", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + EXPECT_EQ("c", negativeRes.offenders[1].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[1].reason); } TEST_F(DocumentationTest, AndOperator) { @@ -1795,7 +1878,8 @@ TEST_F(DocumentationTest, AndOperator) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0]); + EXPECT_EQ("a", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); ghoul::Dictionary negative2 { { "a", 8 } @@ -1803,7 +1887,8 @@ TEST_F(DocumentationTest, AndOperator) { negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0]); + EXPECT_EQ("a", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, OrOperator) { @@ -1835,7 +1920,8 @@ TEST_F(DocumentationTest, OrOperator) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0]); + EXPECT_EQ("a", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, BoolVector2Verifier) { @@ -1854,12 +1940,13 @@ TEST_F(DocumentationTest, BoolVector2Verifier) { EXPECT_EQ(0, positiveRes.offenders.size()); ghoul::Dictionary negative { - { "a", ghoul::Dictionary{ {"1", true}, {"2", 1.0} } } + { "a", ghoul::Dictionary{ { "1", true }, { "2", 1.0 } } } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0]); + EXPECT_EQ("a", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); ghoul::Dictionary negative2 { { "a", true } @@ -1867,7 +1954,8 @@ TEST_F(DocumentationTest, BoolVector2Verifier) { negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0]); + EXPECT_EQ("a", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, IntVector2Verifier) { @@ -1891,7 +1979,8 @@ TEST_F(DocumentationTest, IntVector2Verifier) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0]); + EXPECT_EQ("a", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); ghoul::Dictionary negative2 { { "a", true } @@ -1899,7 +1988,8 @@ TEST_F(DocumentationTest, IntVector2Verifier) { negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0]); + EXPECT_EQ("a", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, DoubleVector2Verifier) { @@ -1923,7 +2013,8 @@ TEST_F(DocumentationTest, DoubleVector2Verifier) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0]); + EXPECT_EQ("a", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); ghoul::Dictionary negative2 { { "a", true } @@ -1931,7 +2022,8 @@ TEST_F(DocumentationTest, DoubleVector2Verifier) { negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0]); + EXPECT_EQ("a", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, BoolVector3Verifier) { @@ -1955,7 +2047,8 @@ TEST_F(DocumentationTest, BoolVector3Verifier) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0]); + EXPECT_EQ("a", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); ghoul::Dictionary negative2 { { "a", true } @@ -1963,7 +2056,8 @@ TEST_F(DocumentationTest, BoolVector3Verifier) { negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0]); + EXPECT_EQ("a", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, IntVector3Verifier) { @@ -1987,7 +2081,8 @@ TEST_F(DocumentationTest, IntVector3Verifier) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0]); + EXPECT_EQ("a", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); ghoul::Dictionary negative2 { { "a", true } @@ -1995,7 +2090,8 @@ TEST_F(DocumentationTest, IntVector3Verifier) { negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0]); + EXPECT_EQ("a", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, DoubleVector3Verifier) { @@ -2019,7 +2115,8 @@ TEST_F(DocumentationTest, DoubleVector3Verifier) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0]); + EXPECT_EQ("a", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); ghoul::Dictionary negative2 { { "a", true } @@ -2027,7 +2124,8 @@ TEST_F(DocumentationTest, DoubleVector3Verifier) { negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0]); + EXPECT_EQ("a", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, BoolVector4Verifier) { @@ -2051,7 +2149,8 @@ TEST_F(DocumentationTest, BoolVector4Verifier) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0]); + EXPECT_EQ("a", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); ghoul::Dictionary negative2 { { "a", true } @@ -2059,7 +2158,8 @@ TEST_F(DocumentationTest, BoolVector4Verifier) { negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0]); + EXPECT_EQ("a", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, IntVector4Verifier) { @@ -2083,7 +2183,8 @@ TEST_F(DocumentationTest, IntVector4Verifier) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0]); + EXPECT_EQ("a", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); ghoul::Dictionary negative2{ { "a", true } @@ -2091,7 +2192,8 @@ TEST_F(DocumentationTest, IntVector4Verifier) { negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0]); + EXPECT_EQ("a", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); } TEST_F(DocumentationTest, DoubleVector4Verifier) { @@ -2115,7 +2217,8 @@ TEST_F(DocumentationTest, DoubleVector4Verifier) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0]); + EXPECT_EQ("a", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); ghoul::Dictionary negative2 { { "a", true } @@ -2123,5 +2226,6 @@ TEST_F(DocumentationTest, DoubleVector4Verifier) { negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0]); + EXPECT_EQ("a", negativeRes.offenders[0].offender); + EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); } From 4e7035a18d90c953f973ea24beec3439320c7d6d Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Sun, 18 Sep 2016 15:31:12 +0200 Subject: [PATCH 83/92] Renaming Offence to Offense Renaming TestResult::offenders to TestResult::offenses --- .../openspace/documentation/documentation.h | 9 +- include/openspace/documentation/verifier.inl | 14 +- src/documentation/documentation.cpp | 36 +- src/documentation/verifier.cpp | 16 +- tests/test_documentation.inl | 756 +++++++++--------- 5 files changed, 418 insertions(+), 413 deletions(-) diff --git a/include/openspace/documentation/documentation.h b/include/openspace/documentation/documentation.h index 10e00ad2a0..3747fc5e47 100644 --- a/include/openspace/documentation/documentation.h +++ b/include/openspace/documentation/documentation.h @@ -39,8 +39,13 @@ namespace documentation { using Optional = ghoul::Boolean; using Exhaustive = ghoul::Boolean; +/** + * The TestResult structure returns the information from the #testSpecification method. It + * contains the information whether test specification test was successful + * (TestResult::success) and a list of Offence%s + */ struct TestResult { - struct Offence { + struct Offense { enum class Reason { MissingKey, ExtraKey, @@ -51,7 +56,7 @@ struct TestResult { Reason reason; }; bool success; - std::vector offenders; + std::vector offenses; }; struct SpecificationError : public ghoul::RuntimeError { diff --git a/include/openspace/documentation/verifier.inl b/include/openspace/documentation/verifier.inl index 2e0891489d..f3256446b3 100644 --- a/include/openspace/documentation/verifier.inl +++ b/include/openspace/documentation/verifier.inl @@ -40,11 +40,11 @@ TestResult TemplateVerifier::operator()(const ghoul::Dictionary& dict, return{ true, {} }; } else { - return { false, { { key, TestResult::Offence::Reason::WrongType } } }; + return { false, { { key, TestResult::Offense::Reason::WrongType } } }; } } else { - return { false, { { key, TestResult::Offence::Reason::MissingKey } } }; + return { false, { { key, TestResult::Offense::Reason::MissingKey } } }; } } @@ -84,7 +84,7 @@ TestResult OperatorVerifier::operator()(const ghoul::Dictionary& dict, return { true, {} }; } else { - return { false, { { key, TestResult::Offence::Reason::Verification }}}; + return { false, { { key, TestResult::Offense::Reason::Verification }}}; } } else { @@ -141,7 +141,7 @@ TestResult InListVerifier::operator()(const ghoul::Dictionary& dict, return { true, {} }; } else { - return { false, { { key, TestResult::Offence::Reason::Verification } } }; + return { false, { { key, TestResult::Offense::Reason::Verification } } }; } } else { @@ -183,7 +183,7 @@ TestResult NotInListVerifier::operator()(const ghoul::Dictionary& dict, return { true, {} }; } else { - return { false, { { key, TestResult::Offence::Reason::Verification } } }; + return { false, { { key, TestResult::Offense::Reason::Verification } } }; } } else { @@ -228,7 +228,7 @@ TestResult InRangeVerifier::operator()(const ghoul::Dictionary& dict, return { true, {} }; } else { - return { false, { { key, TestResult::Offence::Reason::Verification } } }; + return { false, { { key, TestResult::Offense::Reason::Verification } } }; } } else { @@ -258,7 +258,7 @@ TestResult NotInRangeVerifier::operator()(const ghoul::Dictionary& dict, typename T::Type val = dict.value(key); if (val >= lower && val <= upper) { - return { false, { { key, TestResult::Offence::Reason::Verification } } }; + return { false, { { key, TestResult::Offense::Reason::Verification } } }; } else { return { true, {} }; diff --git a/src/documentation/documentation.cpp b/src/documentation/documentation.cpp index 6a1fd379fa..9e223c4786 100644 --- a/src/documentation/documentation.cpp +++ b/src/documentation/documentation.cpp @@ -31,16 +31,16 @@ namespace { const std::string Wildcard = "*"; // Structure used to make offences unique - struct OffenceCompare { - using Offence = openspace::documentation::TestResult::Offence; - bool operator()(const Offence& lhs, const Offence& rhs) const + struct OffenseCompare { + using Offense = openspace::documentation::TestResult::Offense; + bool operator()(const Offense& lhs, const Offense& rhs) const { if (lhs.offender != rhs.offender) { return lhs.offender < rhs.offender; } else { - return std::underlying_type_t(lhs.reason) < - std::underlying_type_t(rhs.reason); + return std::underlying_type_t(lhs.reason) < + std::underlying_type_t(rhs.reason); } } @@ -88,10 +88,10 @@ TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& di TestResult res = verifier(dictionary, key); if (!res.success) { result.success = false; - result.offenders.insert( - result.offenders.end(), - res.offenders.begin(), - res.offenders.end() + result.offenses.insert( + result.offenses.end(), + res.offenses.begin(), + res.offenses.end() ); } } @@ -106,10 +106,10 @@ TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& di TestResult res = verifier(dictionary, p.key); if (!res.success) { result.success = false; - result.offenders.insert( - result.offenders.end(), - res.offenders.begin(), - res.offenders.end() + result.offenses.insert( + result.offenses.end(), + res.offenses.begin(), + res.offenses.end() ); } } @@ -135,8 +135,8 @@ TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& di if (it == d.entries.end()) { result.success = false; - result.offenders.push_back( - { key, TestResult::Offence::Reason::ExtraKey } + result.offenses.push_back( + { key, TestResult::Offense::Reason::ExtraKey } ); } } @@ -144,10 +144,10 @@ TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& di // Remove duplicate offenders that might occur if multiple rules apply to a single // key and more than one of these rules are broken - std::set uniqueOffenders( - result.offenders.begin(), result.offenders.end() + std::set uniqueOffenders( + result.offenses.begin(), result.offenses.end() ); - result.offenders = std::vector( + result.offenses = std::vector( uniqueOffenders.begin(), uniqueOffenders.end() ); diff --git a/src/documentation/verifier.cpp b/src/documentation/verifier.cpp index af51e33c51..4e35f343e8 100644 --- a/src/documentation/verifier.cpp +++ b/src/documentation/verifier.cpp @@ -103,16 +103,16 @@ TestResult IntVerifier::operator()(const ghoul::Dictionary & dict, return { true,{} }; } else { - return { false, { { key, TestResult::Offence::Reason::WrongType } } }; + return { false, { { key, TestResult::Offense::Reason::WrongType } } }; } } else { // If we don't have a double value, we cannot have an int value - return { false, { { key, TestResult::Offence::Reason::WrongType } } }; + return { false, { { key, TestResult::Offense::Reason::WrongType } } }; } } else { - return { false, { {key, TestResult::Offence::Reason::MissingKey }}}; + return { false, { {key, TestResult::Offense::Reason::MissingKey }}}; } } } @@ -137,7 +137,7 @@ TestResult TableVerifier::operator()(const ghoul::Dictionary& dict, ghoul::Dictionary d = dict.value(key); TestResult res = testSpecification({ "", doc, exhaustive }, d); - for (TestResult::Offence& s : res.offenders) { + for (TestResult::Offense& s : res.offenses) { s.offender = key + "." + s.offender; } @@ -145,11 +145,11 @@ TestResult TableVerifier::operator()(const ghoul::Dictionary& dict, } else { if (dict.hasKey(key)) { - return { false, { { key, TestResult::Offence::Reason::WrongType } } }; + return { false, { { key, TestResult::Offense::Reason::WrongType } } }; } else { - return { false, { { key, TestResult::Offence::Reason::MissingKey } } }; + return { false, { { key, TestResult::Offense::Reason::MissingKey } } }; } } } @@ -175,7 +175,7 @@ TestResult AndVerifier::operator()(const ghoul::Dictionary& dict, return { true, {} }; } else { - return { false, { { key, TestResult::Offence::Reason::Verification } } }; + return { false, { { key, TestResult::Offense::Reason::Verification } } }; } } @@ -202,7 +202,7 @@ TestResult OrVerifier::operator()(const ghoul::Dictionary& dict, return { true, {} }; } else { - return { false, { { key, TestResult::Offence::Reason::Verification } } }; + return { false, { { key, TestResult::Offense::Reason::Verification } } }; } } diff --git a/tests/test_documentation.inl b/tests/test_documentation.inl index bff9c7dfb0..a009329d32 100644 --- a/tests/test_documentation.inl +++ b/tests/test_documentation.inl @@ -172,16 +172,16 @@ TEST_F(DocumentationTest, BoolVerifier) { TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Bool", 0} }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Bool", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Bool", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); ghoul::Dictionary negativeExist { { "Bool2", 0} @@ -189,9 +189,9 @@ TEST_F(DocumentationTest, BoolVerifier) { negativeRes = testSpecification(doc, negativeExist); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Bool", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::MissingKey, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Bool", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::MissingKey, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, DoubleVerifier) { @@ -208,7 +208,7 @@ TEST_F(DocumentationTest, DoubleVerifier) { TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Double", 0 } @@ -216,18 +216,18 @@ TEST_F(DocumentationTest, DoubleVerifier) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Double", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); ghoul::Dictionary negativeExist{ { "Double2" , 0.0 } }; negativeRes = testSpecification(doc, negativeExist); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::MissingKey, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Double", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::MissingKey, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, IntVerifier) { @@ -243,14 +243,14 @@ TEST_F(DocumentationTest, IntVerifier) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary positive2 { { "Int", 0.0 } }; positiveRes = testSpecification(doc, positive2); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Int", 0.1 } @@ -258,18 +258,18 @@ TEST_F(DocumentationTest, IntVerifier) { TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Int", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Int", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); ghoul::Dictionary negativeExist { { "Int2", 0 } }; negativeRes = testSpecification(doc, negativeExist); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Int", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::MissingKey, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Int", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::MissingKey, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, StringVerifier) { @@ -286,25 +286,25 @@ TEST_F(DocumentationTest, StringVerifier) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "String", 0 } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("String", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("String", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); ghoul::Dictionary negativeExist { { "String2", ""s } }; negativeRes = testSpecification(doc, negativeExist); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("String", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::MissingKey, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("String", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::MissingKey, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, TableVerifierType) { @@ -320,25 +320,25 @@ TEST_F(DocumentationTest, TableVerifierType) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Table", 0 } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Table", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Table", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); ghoul::Dictionary negativeExist { { "Table2", ghoul::Dictionary{} } }; negativeRes = testSpecification(doc, negativeExist); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Table", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::MissingKey, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Table", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::MissingKey, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, MixedVerifiers) { @@ -365,7 +365,7 @@ TEST_F(DocumentationTest, MixedVerifiers) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative1 { { "Bool", true }, @@ -376,9 +376,9 @@ TEST_F(DocumentationTest, MixedVerifiers) { }; TestResult negativeRes = testSpecification(doc, negative1); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Double", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); ghoul::Dictionary negative2 { { "Bool", true }, @@ -389,11 +389,11 @@ TEST_F(DocumentationTest, MixedVerifiers) { }; negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(2, negativeRes.offenders.size()); - EXPECT_EQ("Int", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); - EXPECT_EQ("String", negativeRes.offenders[1].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[1].reason); + ASSERT_EQ(2, negativeRes.offenses.size()); + EXPECT_EQ("Int", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); + EXPECT_EQ("String", negativeRes.offenses[1].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[1].reason); } TEST_F(DocumentationTest, NestedTables) { @@ -436,7 +436,7 @@ TEST_F(DocumentationTest, NestedTables) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negativeSimple { { "Outer_Int", 1 }, @@ -452,9 +452,9 @@ TEST_F(DocumentationTest, NestedTables) { }; TestResult negativeRes = testSpecification(doc, negativeSimple); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Outer_Table", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Outer_Table", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); ghoul::Dictionary negativeInner { { "Outer_Int", 1 }, @@ -473,9 +473,9 @@ TEST_F(DocumentationTest, NestedTables) { }; negativeRes = testSpecification(doc, negativeInner); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Outer_Table.Inner_Double", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Outer_Table.Inner_Double", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); ghoul::Dictionary negativeInner2 { { "Outer_Int", 1 }, @@ -494,11 +494,11 @@ TEST_F(DocumentationTest, NestedTables) { }; negativeRes = testSpecification(doc, negativeInner2); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(2, negativeRes.offenders.size()); - EXPECT_EQ("Outer_Table.Inner_Double", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); - EXPECT_EQ("Outer_Table.Inner_String", negativeRes.offenders[1].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[1].reason); + ASSERT_EQ(2, negativeRes.offenses.size()); + EXPECT_EQ("Outer_Table.Inner_Double", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); + EXPECT_EQ("Outer_Table.Inner_String", negativeRes.offenses[1].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[1].reason); ghoul::Dictionary negativeInnerSeparate { { "Outer_Int", 1 }, @@ -517,11 +517,11 @@ TEST_F(DocumentationTest, NestedTables) { }; negativeRes = testSpecification(doc, negativeInnerSeparate); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(2, negativeRes.offenders.size()); - EXPECT_EQ("Outer_Table.Inner_Double", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); - EXPECT_EQ("Outer_Table2.Inner_Double2", negativeRes.offenders[1].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[1].reason); + ASSERT_EQ(2, negativeRes.offenses.size()); + EXPECT_EQ("Outer_Table.Inner_Double", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); + EXPECT_EQ("Outer_Table2.Inner_Double2", negativeRes.offenses[1].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[1].reason); ghoul::Dictionary negativeInnerFull { { "Outer_Int", 1 }, @@ -540,13 +540,13 @@ TEST_F(DocumentationTest, NestedTables) { }; negativeRes = testSpecification(doc, negativeInnerFull); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(3, negativeRes.offenders.size()); - EXPECT_EQ("Outer_Table.Inner_Double", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); - EXPECT_EQ("Outer_Table2.Inner_Double2", negativeRes.offenders[1].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[1].reason); - EXPECT_EQ("Outer_Table2.Inner_Table.Inner_Inner_Int", negativeRes.offenders[2].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[2].reason); + ASSERT_EQ(3, negativeRes.offenses.size()); + EXPECT_EQ("Outer_Table.Inner_Double", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); + EXPECT_EQ("Outer_Table2.Inner_Double2", negativeRes.offenses[1].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[1].reason); + EXPECT_EQ("Outer_Table2.Inner_Table.Inner_Inner_Int", negativeRes.offenses[2].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[2].reason); } TEST_F(DocumentationTest, Optional) { @@ -565,7 +565,7 @@ TEST_F(DocumentationTest, Optional) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary positive2 { { "Bool_Force", true }, @@ -573,24 +573,24 @@ TEST_F(DocumentationTest, Optional) { }; positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Bool_Force", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::MissingKey, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Bool_Force", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::MissingKey, negativeRes.offenses[0].reason); ghoul::Dictionary negative2 { { "Bool_Optional", true } }; negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Bool_Force", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::MissingKey, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Bool_Force", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::MissingKey, negativeRes.offenses[0].reason); ghoul::Dictionary negative3 { { "Bool_Force", true }, @@ -598,9 +598,9 @@ TEST_F(DocumentationTest, Optional) { }; negativeRes = testSpecification(doc, negative3); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Bool_Optional", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Bool_Optional", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, RequiredInOptional) { @@ -636,7 +636,7 @@ TEST_F(DocumentationTest, RequiredInOptional) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary positive2 { { @@ -648,21 +648,21 @@ TEST_F(DocumentationTest, RequiredInOptional) { }; positiveRes = testSpecification(doc, positive2); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary positive3 {}; positiveRes = testSpecification(doc, positive3); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "a", ghoul::Dictionary{ { "c", 2 }}} }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a.b", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::MissingKey, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("a.b", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::MissingKey, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, Exhaustive) { @@ -679,29 +679,29 @@ TEST_F(DocumentationTest, Exhaustive) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "False_Int", 1 } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(2, negativeRes.offenders.size()); - EXPECT_EQ("False_Int", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::ExtraKey, negativeRes.offenders[0].reason); - EXPECT_EQ("Int", negativeRes.offenders[1].offender); - EXPECT_EQ(TestResult::Offence::Reason::MissingKey, negativeRes.offenders[1].reason); + ASSERT_EQ(2, negativeRes.offenses.size()); + EXPECT_EQ("False_Int", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::ExtraKey, negativeRes.offenses[0].reason); + EXPECT_EQ("Int", negativeRes.offenses[1].offender); + EXPECT_EQ(TestResult::Offense::Reason::MissingKey, negativeRes.offenses[1].reason); ghoul::Dictionary negative2 { { "Double", 2.0 } }; negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(2, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::ExtraKey, negativeRes.offenders[0].reason); - EXPECT_EQ("Int", negativeRes.offenders[1].offender); - EXPECT_EQ(TestResult::Offence::Reason::MissingKey, negativeRes.offenders[1].reason); + ASSERT_EQ(2, negativeRes.offenses.size()); + EXPECT_EQ("Double", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::ExtraKey, negativeRes.offenses[0].reason); + EXPECT_EQ("Int", negativeRes.offenses[1].offender); + EXPECT_EQ(TestResult::Offense::Reason::MissingKey, negativeRes.offenses[1].reason); } TEST_F(DocumentationTest, NestedExhaustive) { @@ -721,18 +721,18 @@ TEST_F(DocumentationTest, NestedExhaustive) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Table", ghoul::Dictionary{{ "b", 2.0 }}} }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(2, negativeRes.offenders.size()); - EXPECT_EQ("Table.a", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::MissingKey, negativeRes.offenders[0].reason); - EXPECT_EQ("Table.b", negativeRes.offenders[1].offender); - EXPECT_EQ(TestResult::Offence::Reason::ExtraKey, negativeRes.offenders[1].reason); + ASSERT_EQ(2, negativeRes.offenses.size()); + EXPECT_EQ("Table.a", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::MissingKey, negativeRes.offenses[0].reason); + EXPECT_EQ("Table.b", negativeRes.offenses[1].offender); + EXPECT_EQ(TestResult::Offense::Reason::ExtraKey, negativeRes.offenses[1].reason); } TEST_F(DocumentationTest, LessInt) { @@ -748,16 +748,16 @@ TEST_F(DocumentationTest, LessInt) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Int", 10 } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Int", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Int", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, LessDouble) { @@ -773,16 +773,16 @@ TEST_F(DocumentationTest, LessDouble) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Double", 10.0 } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Double", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, LessEqualInt) { @@ -798,23 +798,23 @@ TEST_F(DocumentationTest, LessEqualInt) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary positiveEqual { { "Int", 5 } }; positiveRes = testSpecification(doc, positiveEqual); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Int", 10 } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Int", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Int", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, LessEqualDouble) { @@ -830,23 +830,23 @@ TEST_F(DocumentationTest, LessEqualDouble) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary positiveEqual { { "Double", 5.0 } }; positiveRes = testSpecification(doc, positiveEqual); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Double", 10.0 } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Double", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, GreaterInt) { @@ -862,16 +862,16 @@ TEST_F(DocumentationTest, GreaterInt) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Int", 0 } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Int", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Int", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, GreaterDouble) { @@ -887,16 +887,16 @@ TEST_F(DocumentationTest, GreaterDouble) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Double", 0.0 } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Double", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, GreaterEqualInt) { @@ -912,23 +912,23 @@ TEST_F(DocumentationTest, GreaterEqualInt) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary positiveEqual { { "Int", 5 } }; positiveRes = testSpecification(doc, positiveEqual); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Int", 0 } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Int", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Int", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, GreaterEqualDouble) { @@ -944,23 +944,23 @@ TEST_F(DocumentationTest, GreaterEqualDouble) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary positiveEqual { { "Double", 5.0 } }; positiveRes = testSpecification(doc, positiveEqual); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Double", 0.0 } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Double", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, EqualBool) { @@ -976,16 +976,16 @@ TEST_F(DocumentationTest, EqualBool) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Bool", false } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Bool", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Bool", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, EqualInt) { @@ -1001,16 +1001,16 @@ TEST_F(DocumentationTest, EqualInt) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Int", 0 } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Int", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Int", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, EqualDouble) { @@ -1026,16 +1026,16 @@ TEST_F(DocumentationTest, EqualDouble) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Double", 0.0 } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Double", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, EqualString) { @@ -1052,16 +1052,16 @@ TEST_F(DocumentationTest, EqualString) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "String", "no_string"s } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("String", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("String", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, UnequalBool) { @@ -1077,16 +1077,16 @@ TEST_F(DocumentationTest, UnequalBool) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Bool", true } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Bool", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Bool", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, UnequalInt) { @@ -1102,16 +1102,16 @@ TEST_F(DocumentationTest, UnequalInt) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Int", 1 } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Int", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Int", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, UnequalDouble) { @@ -1127,16 +1127,16 @@ TEST_F(DocumentationTest, UnequalDouble) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Double", 1.0 } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Double", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, UnequalString) { @@ -1153,16 +1153,16 @@ TEST_F(DocumentationTest, UnequalString) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "String", "string"s } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("String", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("String", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, ListBool) { @@ -1178,16 +1178,16 @@ TEST_F(DocumentationTest, ListBool) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Bool", false } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Bool", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Bool", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, ListInt) { @@ -1203,23 +1203,23 @@ TEST_F(DocumentationTest, ListInt) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary positive2 { { "Int", 2 } }; positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Int", 5 } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Int", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Int", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, ListDouble) { @@ -1235,23 +1235,23 @@ TEST_F(DocumentationTest, ListDouble) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary positive2 { { "Double", 2.0 } }; positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Double", 5.0 } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Double", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, ListString) { @@ -1268,23 +1268,23 @@ TEST_F(DocumentationTest, ListString) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary positive2 { { "String", "2"s } }; positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "String", "5"s } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("String", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("String", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, NotListBool) { @@ -1300,16 +1300,16 @@ TEST_F(DocumentationTest, NotListBool) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Bool", true } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Bool", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Bool", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, NotListInt) { @@ -1325,23 +1325,23 @@ TEST_F(DocumentationTest, NotListInt) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary positive2 { { "Int", 3 } }; positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Int", 2 } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Int", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Int", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, NotListDouble) { @@ -1357,23 +1357,23 @@ TEST_F(DocumentationTest, NotListDouble) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary positive2 { { "Double", 3.0 } }; positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Double", 1.0 } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Double", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, NotListString) { @@ -1390,23 +1390,23 @@ TEST_F(DocumentationTest, NotListString) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary positive2 { { "String", "foo_string"s } }; positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "String", "1"s } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("String", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("String", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, AnnotationBool) { @@ -1422,16 +1422,16 @@ TEST_F(DocumentationTest, AnnotationBool) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Bool", 0 } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Bool", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Bool", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, AnnotationInt) { @@ -1447,16 +1447,16 @@ TEST_F(DocumentationTest, AnnotationInt) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Int", 1.1 } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Int", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Int", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, AnnotationDouble) { @@ -1472,16 +1472,16 @@ TEST_F(DocumentationTest, AnnotationDouble) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Double", true } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Double", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, AnnotationString) { @@ -1498,16 +1498,16 @@ TEST_F(DocumentationTest, AnnotationString) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "String", 1 } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("String", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("String", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, AnnotationTable) { @@ -1523,16 +1523,16 @@ TEST_F(DocumentationTest, AnnotationTable) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Table", 1 } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Table", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Table", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, InRangeInt) { @@ -1548,30 +1548,30 @@ TEST_F(DocumentationTest, InRangeInt) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary positive2 { { "Int", 0 } }; positiveRes = testSpecification(doc, positive2); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary positive3 { { "Int", 5 } }; positiveRes = testSpecification(doc, positive3); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Int", 10 } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Int", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Int", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, InRangeDouble) { @@ -1587,37 +1587,37 @@ TEST_F(DocumentationTest, InRangeDouble) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary positive2 { { "Double", 0.0 } }; positiveRes = testSpecification(doc, positive2); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary positive3 { { "Double", 5.0 } }; positiveRes = testSpecification(doc, positive3); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary positive4 { { "Double", 1.5 } }; positiveRes = testSpecification(doc, positive4); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Double", 10.0 } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Double", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, NotInRangeInt) { @@ -1633,41 +1633,41 @@ TEST_F(DocumentationTest, NotInRangeInt) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary positive2 { { "Int", 6 } }; positiveRes = testSpecification(doc, positive2); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Int", 2 } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Int", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Int", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); ghoul::Dictionary negative2 { { "Int", 0 } }; negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Int", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Int", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); ghoul::Dictionary negative3 { { "Int", 5 } }; negativeRes = testSpecification(doc, negative3); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Int", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Int", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, NotInRangeDouble) { @@ -1683,41 +1683,41 @@ TEST_F(DocumentationTest, NotInRangeDouble) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary positive2 { { "Double", 6.0 } }; positiveRes = testSpecification(doc, positive2); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "Double", 0.0 } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Double", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); ghoul::Dictionary negative2 { { "Double", 5.0 } }; negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Double", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); ghoul::Dictionary negative3 { { "Double", 2.5 } }; negativeRes = testSpecification(doc, negative3); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("Double", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Double", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, Wildcard) { @@ -1735,7 +1735,7 @@ TEST_F(DocumentationTest, Wildcard) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "a", false }, @@ -1744,9 +1744,9 @@ TEST_F(DocumentationTest, Wildcard) { }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("a", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); ghoul::Dictionary negative2 { { "a", false }, @@ -1755,11 +1755,11 @@ TEST_F(DocumentationTest, Wildcard) { }; negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(2, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); - EXPECT_EQ("b", negativeRes.offenders[1].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[1].reason); + ASSERT_EQ(2, negativeRes.offenses.size()); + EXPECT_EQ("a", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); + EXPECT_EQ("b", negativeRes.offenses[1].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[1].reason); ghoul::Dictionary negative3 { { "a", false }, @@ -1768,13 +1768,13 @@ TEST_F(DocumentationTest, Wildcard) { }; negativeRes = testSpecification(doc, negative3); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(3, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); - EXPECT_EQ("b", negativeRes.offenders[1].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[1].reason); - EXPECT_EQ("c", negativeRes.offenders[2].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[2].reason); + ASSERT_EQ(3, negativeRes.offenses.size()); + EXPECT_EQ("a", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); + EXPECT_EQ("b", negativeRes.offenses[1].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[1].reason); + EXPECT_EQ("c", negativeRes.offenses[2].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[2].reason); } TEST_F(DocumentationTest, WildcardMixed) { @@ -1795,7 +1795,7 @@ TEST_F(DocumentationTest, WildcardMixed) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "a", false }, @@ -1804,11 +1804,11 @@ TEST_F(DocumentationTest, WildcardMixed) { }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(2, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); - EXPECT_EQ("b", negativeRes.offenders[1].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[1].reason); + ASSERT_EQ(2, negativeRes.offenses.size()); + EXPECT_EQ("a", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); + EXPECT_EQ("b", negativeRes.offenses[1].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[1].reason); ghoul::Dictionary negative2 { { "a", false }, @@ -1817,11 +1817,11 @@ TEST_F(DocumentationTest, WildcardMixed) { }; negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(2, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); - EXPECT_EQ("b", negativeRes.offenders[1].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[1].reason); + ASSERT_EQ(2, negativeRes.offenses.size()); + EXPECT_EQ("a", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); + EXPECT_EQ("b", negativeRes.offenses[1].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[1].reason); ghoul::Dictionary negative3 { { "a", false }, @@ -1830,13 +1830,13 @@ TEST_F(DocumentationTest, WildcardMixed) { }; negativeRes = testSpecification(doc, negative3); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(3, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); - EXPECT_EQ("b", negativeRes.offenders[1].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[1].reason); - EXPECT_EQ("c", negativeRes.offenders[2].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[2].reason); + ASSERT_EQ(3, negativeRes.offenses.size()); + EXPECT_EQ("a", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); + EXPECT_EQ("b", negativeRes.offenses[1].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[1].reason); + EXPECT_EQ("c", negativeRes.offenses[2].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[2].reason); ghoul::Dictionary negative4 { { "a", false }, @@ -1845,11 +1845,11 @@ TEST_F(DocumentationTest, WildcardMixed) { }; negativeRes = testSpecification(doc, negative4); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(2, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); - EXPECT_EQ("c", negativeRes.offenders[1].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[1].reason); + ASSERT_EQ(2, negativeRes.offenses.size()); + EXPECT_EQ("a", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); + EXPECT_EQ("c", negativeRes.offenses[1].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[1].reason); } TEST_F(DocumentationTest, AndOperator) { @@ -1870,25 +1870,25 @@ TEST_F(DocumentationTest, AndOperator) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "a", 0 } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("a", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); ghoul::Dictionary negative2 { { "a", 8 } }; negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("a", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, OrOperator) { @@ -1905,23 +1905,23 @@ TEST_F(DocumentationTest, OrOperator) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary positive2 { { "a", 1 } }; positiveRes = testSpecification(doc, positive2); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "a", false } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::Verification, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("a", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::Verification, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, BoolVector2Verifier) { @@ -1937,25 +1937,25 @@ TEST_F(DocumentationTest, BoolVector2Verifier) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "a", ghoul::Dictionary{ { "1", true }, { "2", 1.0 } } } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("a", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); ghoul::Dictionary negative2 { { "a", true } }; negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("a", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, IntVector2Verifier) { @@ -1971,25 +1971,25 @@ TEST_F(DocumentationTest, IntVector2Verifier) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "a", ghoul::Dictionary{ { "1", true },{ "2", 1 } } } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("a", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); ghoul::Dictionary negative2 { { "a", true } }; negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("a", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, DoubleVector2Verifier) { @@ -2005,25 +2005,25 @@ TEST_F(DocumentationTest, DoubleVector2Verifier) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "a", ghoul::Dictionary{ { "1", true }, { "2", 1.0 } } } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("a", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); ghoul::Dictionary negative2 { { "a", true } }; negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("a", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, BoolVector3Verifier) { @@ -2039,25 +2039,25 @@ TEST_F(DocumentationTest, BoolVector3Verifier) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "a", ghoul::Dictionary{ { "1", true },{ "2", 1.0 }, { "3", "s" } } } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("a", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); ghoul::Dictionary negative2 { { "a", true } }; negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("a", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, IntVector3Verifier) { @@ -2073,25 +2073,25 @@ TEST_F(DocumentationTest, IntVector3Verifier) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "a", ghoul::Dictionary{ { "1", true },{ "2", 1 }, { "3", "s" } } } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("a", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); ghoul::Dictionary negative2 { { "a", true } }; negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("a", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, DoubleVector3Verifier) { @@ -2107,25 +2107,25 @@ TEST_F(DocumentationTest, DoubleVector3Verifier) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "a", ghoul::Dictionary{ { "1", true },{ "2", 1.0 }, { "3", "s"} } } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("a", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); ghoul::Dictionary negative2 { { "a", true } }; negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("a", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, BoolVector4Verifier) { @@ -2141,25 +2141,25 @@ TEST_F(DocumentationTest, BoolVector4Verifier) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "a", ghoul::Dictionary{ { "1", true },{ "2", 1.0 }, { "3", "s" }, { "4", 1 }}} }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("a", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); ghoul::Dictionary negative2 { { "a", true } }; negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("a", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, IntVector4Verifier) { @@ -2175,25 +2175,25 @@ TEST_F(DocumentationTest, IntVector4Verifier) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "a", ghoul::Dictionary{ { "1", true },{ "2", 1 },{ "3", "s" }, { "4", 1 } } } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("a", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); ghoul::Dictionary negative2{ { "a", true } }; negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("a", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); } TEST_F(DocumentationTest, DoubleVector4Verifier) { @@ -2209,23 +2209,23 @@ TEST_F(DocumentationTest, DoubleVector4Verifier) { }; TestResult positiveRes = testSpecification(doc, positive); EXPECT_TRUE(positiveRes.success); - EXPECT_EQ(0, positiveRes.offenders.size()); + EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { { "a", ghoul::Dictionary{ { "1", true },{ "2", 1.0 },{ "3", "s" }, { "4", 1 } } } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("a", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); ghoul::Dictionary negative2 { { "a", true } }; negativeRes = testSpecification(doc, negative2); EXPECT_FALSE(negativeRes.success); - ASSERT_EQ(1, negativeRes.offenders.size()); - EXPECT_EQ("a", negativeRes.offenders[0].offender); - EXPECT_EQ(TestResult::Offence::Reason::WrongType, negativeRes.offenders[0].reason); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("a", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); } From 29c989ab8291152e3f2ec990812bc356e0c96fe7 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Sun, 18 Sep 2016 20:47:41 +0200 Subject: [PATCH 84/92] Add documentation to the documentation and verifier classes Add static const member variable to the DocumentationEntry class for Wildcards --- .../openspace/documentation/documentation.h | 182 ++++++- include/openspace/documentation/verifier.h | 482 +++++++++++++++++- include/openspace/documentation/verifier.inl | 54 +- include/openspace/scene/scene.h | 2 +- include/openspace/scene/scenegraphnode.h | 2 +- modules/toyvolume/toyvolumemodule.cpp | 1 - src/documentation/documentation.cpp | 102 ++-- src/documentation/documentationengine.cpp | 7 +- src/documentation/verifier.cpp | 61 ++- tests/test_documentation.inl | 201 +++++++- 10 files changed, 952 insertions(+), 142 deletions(-) diff --git a/include/openspace/documentation/documentation.h b/include/openspace/documentation/documentation.h index 3747fc5e47..684e25b7fa 100644 --- a/include/openspace/documentation/documentation.h +++ b/include/openspace/documentation/documentation.h @@ -42,60 +42,220 @@ using Exhaustive = ghoul::Boolean; /** * The TestResult structure returns the information from the #testSpecification method. It * contains the information whether test specification test was successful - * (TestResult::success) and a list of Offence%s + * (TestResult::success) and a list of TestResult::Offense%s (TestResult::offenses). If + * TestResult::success is true, TestResult::offenses is guaranteed to be empty. */ struct TestResult { + /** + * An Offense is a violation against a specific verifier. The Offense::offender is the + * key that caused the offense (in the case of nested tables, it will be fully + * qualified identifier) and the Offense::Reason is the reason that caused the + * offense. + */ struct Offense { + /** + * The Reason for the offense + */ enum class Reason { - MissingKey, - ExtraKey, - WrongType, - Verification + MissingKey, ///< The offending key that was requested was not found + ExtraKey, ///< The exhaustive documentation contained an extra key + WrongType, ///< The key's value was not of the expected type + Verification ///< The value did not pass a necessary non-type verifier }; + /// The offending key that caused the Offense. In the case of a nested table, + /// this value will be the fully qualified name of the key std::string offender; + /// The Reason that caused this offense Reason reason; }; + /// Is \c true if the TestResult is positive, \c false otherwise bool success; + /// Contains a list of offenses that were found in the test. Is empty if + /// TestResult::Success is \c true std::vector offenses; }; +/** + * This exception is thrown by the #testSpecificationAndThrow method if the test detected + * a specification violation. This class contains the TestResult that would have otherwise + * be returned in a call to #testSpecification. + */ struct SpecificationError : public ghoul::RuntimeError { + /** + * Creates the SpecificationError exception instance. + * \param result The offending TestResult that is passed on + * \param component The component that initiated the specification test + * \pre \p result%'s TestResult::success must be \c false + */ SpecificationError(TestResult result, std::string component); + /// The TestResult that caused the SpecificationError to be thrown TestResult result; }; struct Verifier; +/** + * A DocumentationEntry provides the specification for a single key, which is tested using + * the provided Verifier. Each DocumentationEntry can contain a textual documentation that + * describes the entry and is printed when the documentation for a Documentation is + * requested. Lastly, each DocumentationEntry can be Optional. If the provided key is the + * DocumentationEntry::Wildcard, any key in the containing Documentation will be tested + * against the provided verifier. The most convenient way of creating DocumentationEntry%s + * is by using an inline initializer list such as: + *\verbatim +DocumentationEntry e = { "key", new IntVerifier, "Documentation text", Optional::Yes }; +\endverbatim + + * Furthermore, these initializer lists can be crated all at once for a Documentation. + * Even if the Verifier%s are specified using the \c new operators, they will not leak + * memory as the DocumentationEntry takes ownership of them in the constructor. + */ struct DocumentationEntry { - DocumentationEntry(std::string key, Verifier* t, std::string doc = "", + /// The wildcard character that will match against every key in a Documentation + static const std::string Wildcard; + + /** + * The constructor for a DocumentationEntry describing a \p key in a Documentation. + * The value for the key (or each value in the case of the + * DocumentationEntry::Wildcard) is tested using the \p verifier, that specifies the + * conditions that the \p key%'s value has to fulfill. The textual documentation + * \p doc shall describe the usage of the key-value pair and will be printed for human + * consumption for example in the DocumentationEngine. Each DocumentationEntry can + * further be \p optional. + * \param key The key for which this DocumentationEntry is valid. If this valid is + * equal to DocumentationEntry::Wildcard, each entry in the Documentation that + * contains this DocumentationEntry will be matched + * \param verifier The Verifier that is used to test the \p key%'s value to determine + * if it is a valid value + * \param doc The textual documentation that describes the DocumentationEntry in a + * human readable format + * \param optional Determines whether the Documentation containing this + * DocumentationEntry must have a key \p key, or whether it is optional + * \pre \p key must not be empty + * \pre \p verifier must not be nullptr + */ + DocumentationEntry(std::string key, std::shared_ptr verifier, + std::string doc = "", Optional optional = Optional::No); + + /** + * The constructor for a DocumentationEntry describing a \p key in a Documentation. + * The value for the key (or each value in the case of the + * DocumentationEntry::Wildcard) is tested using the \p verifier, that specifies the + * conditions that the \p key%'s value has to fulfill. The textual documentation + * \p doc shall describe the usage of the key-value pair and will be printed for human + * consumption for example in the DocumentationEngine. Each DocumentationEntry can + * further be \p optional. + * \param key The key for which this DocumentationEntry is valid. If this valid is + * equal to DocumentationEntry::Wildcard, each entry in the Documentation that + * contains this DocumentationEntry will be matched + * \param verifier The Verifier that is used to test the \p key%'s value to determine + * if it is a valid value. The DocumentationEntry will take ownership of the passed + * object + * \param doc The textual documentation that describes the DocumentationEntry in a + * human readable format + * \param optional Determines whether the Documentation containing this + * DocumentationEntry must have a key \p key, or whether it is optional + * \pre \p key must not be empty + * \pre \p verifier must not be nullptr + */ + DocumentationEntry(std::string key, Verifier* verifier, std::string doc = "", Optional optional = Optional::No); + /// The key that is described by this DocumentationEntry std::string key; + /// The Verifier that is used to test the key's value std::shared_ptr verifier; - bool optional; + /// Determines whether the described DocumentationEntry is optional or not + Optional optional; + /// The textual description of this DocumentationEntry std::string documentation; }; -using DocumentationEntries = std::vector; +/** + * This struct contains the documentation and specification for a ghoul::Dictionary. It is + * used to impose restrictions on keys and values and determine whether a given + * ghoul::Dictionary adheres to these specifications (see #testSpecification and + * #testSpecificationAndThrow methods). Each Documentation consists of a human-readable + * \c name, a list of DocumentationEntry%s that each describe a single key value, and a + * flag whether these entries are Exhaustive or not. If a Documentation is Exhaustive, a + * ghoul::Dictionary that contains additional keys will fail the specification, whereas a + * non-exhaustive Documentation allow for other (potentially non used) keys. The most + * convenient way of creating a Documentation is by using nested initializer lists: + *\verbatim +Documentation doc = { + "Documentation for an arbitrary dictionary", + { // A list of DocumentationEntry%s; also specified using initializer lists + { "key1", new IntVerifier, "Documentation key1", Optional::Yes }, + { "key2", new FloatVerifier, "Documentation key2" }, + { "key3", new StringVerifier } + }, + Exhaustive::Yes ++; +\endverbatim + * + * If multiple DocumentationEntries cover the same key, they are all evaluated for that + * specific key. The same holds true if there is a DocumentationEntry with a + * DocumentationEntry::Wildcard and a more specialized DocumentationEntry. In this case, + * both the wildcard and the specialized entry will be evaluated. + */ struct Documentation { + using DocumentationEntries = std::vector; + + /** + * Creates a Documentation with a human-readable \p name and a list of \p entries. + * \param name The human-readable name of this Documentation + * \param entries A list of DocumentationEntry%s that describe the individual keys for + * this entrie Documentation + * \param exhaustive Determines whether the \p entries are an exhaustive specification + * of the object or whether additional, potentially unused, keys are allowed + */ Documentation(std::string name = "", DocumentationEntries entries = {}, Exhaustive exhaustive = Exhaustive::No); - Documentation(DocumentationEntries entries); + /// The human-readable name of the Documentation std::string name; + /// A list of specifications that are describing this Documentation DocumentationEntries entries; + /// A flag to say wheter the DocumentationEntries are an exhaustive description Exhaustive exhaustive; }; +/** + * This method tests whether a provided ghoul::Dictionary \p dictionary adheres to the + * specification \p documentation and returns its result as a TestResult. The TestResult + * will contain whether the \p dictionary adheres to the \p documentation and, in + * addition, the list of all offending keys together with the reason why they are + * offending. + * \param documentation The Documentation that the \p dictionary is tested against + * \param dictionary The ghoul::Dictionary that is to be tested against the + * \p documentation + * \return A TestResult that contains the results of the specification testing + */ +TestResult testSpecification(const Documentation& documentation, + const ghoul::Dictionary& dictionary); -TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& dictionary); -void testSpecificationAndThrow(const Documentation& doc, +/** +* This method tests whether a provided ghoul::Dictionary \p dictionary adheres to the +* specification \p documentation. If the \p dictionary does not adhere to the +* specification a SpecificationError is thrown, and the exception contains the TestResult +* that contains more information about the offending keys. If the \p dictionary adheres to +* the \p documentation, the method returns normally. +* \param documentation The Documentation that the \p dictionary is tested against +* \param dictionary The ghoul::Dictionary that is to be tested against the +* \p documentation +* \param component The component that is using this method; this argument is passed to the +* SpecificationError that is thrown in case of not adhering to the \p documentation +* \throw SpecificationError If the \p dictionary does not adhere to the \p documentation +*/ +void testSpecificationAndThrow(const Documentation& documentation, const ghoul::Dictionary& dictionary, std::string component); } // namespace documentation +// We want to make it easier for people to use it, so we pull the Documentation class into +// the openspace namespace using documentation::Documentation; } // namespace openspace diff --git a/include/openspace/documentation/verifier.h b/include/openspace/documentation/verifier.h index 4152f76135..d27a633453 100644 --- a/include/openspace/documentation/verifier.h +++ b/include/openspace/documentation/verifier.h @@ -32,31 +32,107 @@ namespace openspace { namespace documentation { +/** + * The base class of all Verifier%s. Each object must have an Verifier::operator() + * overload, that performs the actual testing of the key inside the passed + * ghoul::Dictionary and return a TestResult. The Verifier::type method returns a + * human-readable representation of the type that is expected by the concret subclass of + * Verifier. Furthermore, the Verifier::documentation method returns a human-readable + * description of the Verifier subclass and what it tests for. + */ struct Verifier { - virtual TestResult operator()(const ghoul::Dictionary& dict, + /** + * This method tests whether the \p key contained in the \p dictionary adheres to + * whatever the concrete Verifer needs to test. The actual testing depends on the + * concrete subclass and can range from type testing (for example IntVerifier or + * StringVerifier) to more complex testing (for example DoubleInRangeVerifier or + * TableVerifier). + * \param dictionary The dictionary that contains the \p key which is to be tested by + * this Verifier + * \param key The key inside the \p dictionary that is to be tested + * \return A TestResult struct that contains information about whether the key adheres + * to the demands of the specific Verifier. If it does not, TestResult::offenders will + * either contain \p key or, in the case of a TableVerifier, a list of all offending + * subkeys as fully qualified names. + * \post If the return values' TestResult::success is \c true, its + * TestResult::offenders is empty + */ + virtual TestResult operator()(const ghoul::Dictionary& dictionary, const std::string& key) const = 0; + /** + * This method returns a human-readable string describing the type of object that is + * handled by the Verifier subclass. This is only used for generating a human-readable + * documentation and description of a Documenation object. + * \return A human-readable string describing the type of object for the Verifier + * \post The return value is not empty + */ virtual std::string type() const = 0; - virtual std::string documentation() const; + + /** + * This method returns a human-readable string describing the tests that the concrete + * Verifier subclass implements. This is only used for generating a human-readable + * documentation and description of a Documentation object. + * \return A human-readable string describing the tests that are performed by the + * Verifier + * \post The return value is not empty + */ + virtual std::string documentation() const = 0; }; +//---------------------------------------------------------------------------------------- // General verifiers +//---------------------------------------------------------------------------------------- + +/** + * The base class Verifier for all Verifier%s that have to test against a specific value + * type. This Verifier tests whether a given key exists and whether it has the same type + * as the template parameter \c T. + * \tparam T The type against which the key's value is tested + */ template struct TemplateVerifier : public Verifier { using Type = T; - TestResult operator()(const ghoul::Dictionary& dict, + /** + * Tests whether the \p key contained in the ghoul::Dictionary \p dictionary exists + * and has the same type as \c T. + * \param dictionary The ghoul::Dictionary that contains the \p key to be tested + * \param key The key inside the \p dictinoary that is to be tested + * \return A TestResult that contains the information whether the \p key exists in the + * \p dictionary and whether the key's value's type agrees with \c T. + * \post The return values' TestResult::success is either \c true and + * TestResult::offenders is empty, or it is \c false and TestResult::offenders + * contains \p key + */ + TestResult operator()(const ghoul::Dictionary& dictionary, const std::string& key) const override; + + std::string documentation() const override; }; +/** + * A Verifier that checks whether a given key inside a ghoul::Dictionary is of type + * \c bool. No implicit conversion is considered in this testing. + */ struct BoolVerifier : public TemplateVerifier { std::string type() const override; }; +/** +* A Verifier that checks whether a given key inside a ghoul::Dictionary is of type +* \c double. No implicit conversion is considered in this testing. +*/ struct DoubleVerifier : public TemplateVerifier { std::string type() const override; }; +/** +* A Verifier that checks whether a given key inside a ghoul::Dictionary is of type +* \c int. It will also return \c true if the key's value is of type \c double, but is a +* integer value (for example, 0.0, 12.0, but not +* 0.5). +*/ struct IntVerifier : public TemplateVerifier { TestResult operator()(const ghoul::Dictionary& dict, const std::string& key) const override; @@ -64,51 +140,154 @@ struct IntVerifier : public TemplateVerifier { std::string type() const override; }; +/** +* A Verifier that checks whether a given key inside a ghoul::Dictionary is of type +* std::string. No implicit conversion is considered in this testing. +*/ struct StringVerifier : public TemplateVerifier { std::string type() const override; }; +/** +* A Verifier that checks whether a given key inside a ghoul::Dictionary is another +* ghoul::Dictionary. The constructor takes a list of DocumentationEntry%s, which are used +* recursively to check the contained table. If this list is empty, a simple type testing +* is performed instead. If the testing finds any offending keys, it will return those keys +* with fully qualified names, that is, the name of the table will be prepended to the +* offending keys. Example: If the key \c Table is tested and a passed DocumentationEntry +* checks for a nested key \c a and this does not comply, this Verifier will return +* Table.a as an offender. +*/ struct TableVerifier : public TemplateVerifier { - TableVerifier(std::vector d = {}, + /** + * This constructor takes a list of DocumentationEntry%s that are used recursively to + * check the table (= ghoul::Dictionary) contained in the key's value. Similar to the + * Documentation, these DocumentationEntry%s can be Exhaustive or not. + * \param documentationEntries The DocumentationEntry%s that are used to recursively + * test the ghoul::Dictionary that is contained inside. If this list is empty, only a + * type check is performed + * \param exhaustive Whether the DocumentationEntry%s contained in + * \p documentationEntries completely describe the contained table or whether + * additional keys are allowed + */ + TableVerifier(std::vector documentationEntries = {}, Exhaustive exhaustive = Exhaustive::No); - TestResult operator()(const ghoul::Dictionary& dict, + /** + * Checks whether the \p key%'s value is a table (= ghoul::Dictionary) and (if + * provided) recursively checks whether the table adheres to the DocumentationEntry%s + * provided in the constructor. If the testing finds any offending keys, it will + * return those keys with fully qualified names, that is, the name of the table will + * be prepended to the offending keys. + * \param dictionary The ghoul::Dictionary that is to be tested for the \p key + * \param key The key for which the \p dictionary is tested + * \return A TestResult containing the results of the testing. If DocumentationEntry%s + * were specified in the constructor and one of those values find an offending key + * inside the table, it's name will be returned with a fully qualified name by + * prepending the name (= \key) of the table. + */ + TestResult operator()(const ghoul::Dictionary& dictionary, const std::string& key) const override; std::string type() const override; - std::vector doc; + /// The documentations passed in the constructor + std::vector documentations; + /// Flag that specifies whether the TableVerifier::documentation exhaustively + /// describes the table or whether additional keys are allowed Exhaustive exhaustive; }; +//---------------------------------------------------------------------------------------- +// Vector verifiers +//---------------------------------------------------------------------------------------- + +/** + * This struct is the base class for all Verifier%s that check for \c glm vector types. + * The template parameter for the subclasses is the containing type, not the full vector + * type. For example to check for glm::dvec3, one would create a + * Vector3Verifier. + */ struct VectorVerifier {}; +/** + * This Verifier checks whether the value is of type glm::tvec2 + */ template struct Vector2Verifier : public TemplateVerifier>, public VectorVerifier { std::string type() const override; }; +/** +* This Verifier checks whether the value is of type glm::tvec3 +*/ template struct Vector3Verifier : public TemplateVerifier>, public VectorVerifier { std::string type() const override; }; +/** +* This Verifier checks whether the value is of type glm::tvec4 +*/ template struct Vector4Verifier : public TemplateVerifier>, public VectorVerifier { std::string type() const override; }; -// Operator Verifiers -template +//---------------------------------------------------------------------------------------- +// Operator verifiers +//---------------------------------------------------------------------------------------- + +/** + * This is the abstract base class of all binary operator-based verifiers. This class + * takes two template parameters. The first is the Verifier that one would use to only + * check for the type of the object, for example IntVerifier. The second argument is a + * function object that has its operator() function overloaded and returns a + * boolean value. In these cases, the \c std function objects std::less, + * std::equal_to, etc are used. + * + * This verifier will apply the \c Operator to the stored value and the incoming value + * (after type checking) and will check if the \c Operator returns \c true or \c false. + * The incoming value is used as the first argument and the stored value as the second + * argument to the \c Operator. If the type checking fails, the offense reason + * TestResult::Offense::Reason::WrongType is returned. If the \c Operator fails, the + * reason TestResult::Offense::Verification is returned instead. + */ +template struct OperatorVerifier : public T { + /** + * Constructor for an OperatorVerifier. As all operators need to compare the incoming + * value to a stored value, we require the comparison \p value to be passed in here. + * \param value The value against which the tested value is compared using the + * \c Operator + */ OperatorVerifier(typename T::Type value); - TestResult operator()(const ghoul::Dictionary& dict, + /** + * First checks whether the \p dictionary contains the passed \p key and whether the + * \p key%'s value is correct using the template paramater \c T as a verifier. Then, + * the \p key%'s value is checked against the stored OperatorVerifier::value using the + * \c Operator. + * \param dictionary The ghoul::Dictionary that contains the \p key to be tested + * \param key The key inside the \p dictinoary that is to be tested + * \return A TestResult containing the results of the specification testing. If the + * \p key%'s value has the wrong type, it will be added to the TestResult's offense + * list with the reason TestResult::Offense::Reason::WrongType; if the \c Operator + * returns false, it will be added with the reason TestResult::Offense::Verification + * instead. + */ + TestResult operator()(const ghoul::Dictionary& dictionary, const std::string& key) const override; + /// The stored value which is passed to the \c Operator as a second argument typename T::Type value; }; +/** + * This Verifier checks whether the incoming value is strictly smaller than the stored + * value. Due to the operator type restrictions, \c T cannot be a subclass of (or the same + * as) BoolVerifier, StringVerifier, TableVerifier, or VectorVerifier. + */ template struct LessVerifier : public OperatorVerifier> { static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); @@ -121,6 +300,11 @@ struct LessVerifier : public OperatorVerifier> { std::string documentation() const; }; +/** +* This Verifier checks whether the incoming value is smaller than or equal to the stored +* value. Due to the operator type restrictions, \c T cannot be a subclass of (or the same +* as) BoolVerifier, StringVerifier, TableVerifier, or VectorVerifier. +*/ template struct LessEqualVerifier : public OperatorVerifier> { static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); @@ -133,6 +317,11 @@ struct LessEqualVerifier : public OperatorVerifier struct GreaterVerifier : public OperatorVerifier> { static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); @@ -145,6 +334,11 @@ struct GreaterVerifier : public OperatorVerifier struct GreaterEqualVerifier : public OperatorVerifier> { static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); @@ -157,6 +351,10 @@ struct GreaterEqualVerifier : public OperatorVerifier struct EqualVerifier : public OperatorVerifier> { static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); @@ -166,6 +364,11 @@ struct EqualVerifier : public OperatorVerifier struct UnequalVerifier : public OperatorVerifier> { static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); @@ -175,29 +378,77 @@ struct UnequalVerifier : public OperatorVerifier struct InListVerifier : public T { static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + /** + * Constructs an InListVerifier that checks whether the incoming value is of the + * correct type and whether the value is part of the list passed as \p values. + * \param values The list of values against which the incoming value is tested + */ InListVerifier(std::vector values); - TestResult operator()(const ghoul::Dictionary& dict, + /** + * Tests whether the \p key exists in the \p dictionary, whether it has the correct + * type by invoking the template parameter \c T, and then tests if the \p key's value + * is part of the list passed to the constructor. + * \param dictionary The ghoul::Dictionary that contains the \p key + * \param key The key that is contained in the \p dictionary and whose value is tested + * \return A TestResult containing the results of the specification testing. If the + * \p key%'s value has the wrong type, it will be added to the TestResult's offense + * list with the reason TestResult::Offense::Reason::WrongType; if the value is not + * in the list, it will be added with the reason TestResult::Offense::Verification + * instead. + */ + TestResult operator()(const ghoul::Dictionary& dictionary, const std::string& key) const override; std::string documentation() const override; + /// The list of values against which the incoming value is tested std::vector values; }; +/** +* This Verifier checks whether the incoming value is of the correct type, using the +* Verifier passed as a template parameter \c T and then checks whether it is not part of a +* list that is passed to the constructor. To the missing equality operator, \c T cannot +* be a subclass of (or the same as) TableVerifier. +*/ template struct NotInListVerifier : public T { static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); + /** + * Constructs a NotInListVerifier that checks whether the incoming value is of the + * correct type and whether the value is not part of the list passed as \p values. + * \param values The list of values against which the incoming value is tested + */ NotInListVerifier(std::vector values); - TestResult operator()(const ghoul::Dictionary& dict, + /** + * Tests whether the \p key exists in the \p dictionary, whether it has the correct + * type by invoking the template parameter \c T, and then tests if the \p key's value + * is not part of the list passed to the constructor. + * \param dictionary The ghoul::Dictionary that contains the \p key + * \param key The key that is contained in the \p dictionary and whose value is tested + * \return A TestResult containing the results of the specification testing. If the + * \p key%'s value has the wrong type, it will be added to the TestResult's offense + * list with the reason TestResult::Offense::Reason::WrongType; if the value is in the + * list, it will be added with the reason TestResult::Offense::Verification instead. + */ + TestResult operator()(const ghoul::Dictionary& dictionary, const std::string& key) const override; std::string documentation() const override; @@ -205,7 +456,17 @@ struct NotInListVerifier : public T { std::vector values; }; -// Range Verifiers +//---------------------------------------------------------------------------------------- +// Range verifiers +//---------------------------------------------------------------------------------------- + +/** +* This Verifier checks whether the incoming value is of the correct type, using the +* Verifier passed as a template parameter \c T and then checks whether it is greater or +* equal to a lower limit and less or equal to a higher limit. To the missing comparison +* operators, \c T cannot be a subclass of (or the same as) BoolVerifier, StringVerifier, +* TableVerifier, or VectorVerifier. Both the lower and the higher limit are inclusive). +*/ template struct InRangeVerifier : public T { static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); @@ -213,9 +474,30 @@ struct InRangeVerifier : public T { static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); static_assert(!std::is_base_of_v, "T cannot be VectorVerifier"); + /** + * Constructs a InRangeVerifier that checks whether the incoming value is of the + * correct type and whether the value is greater or equal to \p lower and less or equal + * to \upper. + * \param lower The (inclusive) lower limit of the range + * \param upper The (inclusive) upper limit of the range + * \pre \p lower must be smaller or equal to \p upper + */ InRangeVerifier(typename T::Type lower, typename T::Type upper); - TestResult operator()(const ghoul::Dictionary& dict, + /** + * Tests whether the \p key exists in the \p dictionary, whether it has the correct + * type by invoking the template parameter \c T, and then tests if the \p key's value + * is between the lower and upper limits (both inclusive) that were passed to the + * constructor. + * \param dictionary The ghoul::Dictionary that contains the \p key + * \param key The key that is contained in the \p dictionary and whose value is tested + * \return A TestResult containing the results of the specification testing. If the + * \p key%'s value has the wrong type, it will be added to the TestResult's offense + * list with the reason TestResult::Offense::Reason::WrongType; if the value is outside + * the range defined by the lower and upper limits passed to the constructor, it will + * be added with the reason TestResult::Offense::Verification instead. + */ + TestResult operator()(const ghoul::Dictionary& dictionary, const std::string& key) const override; std::string documentation() const override; @@ -224,6 +506,13 @@ struct InRangeVerifier : public T { typename T::Type upper; }; +/** +* This Verifier checks whether the incoming value is of the correct type, using the +* Verifier passed as a template parameter \c T and then checks whether it is outside the +* (exclusive) range defined by a lower and upper limit. To the missing comparison +* operators, \c T cannot be a subclass of (or the same as) BoolVerifier, StringVerifier, +* TableVerifier, or VectorVerifier. Both the lower and the higher limit are exclusive). +*/ template struct NotInRangeVerifier : public T { static_assert(!std::is_base_of_v, "T cannot be BoolVerifier"); @@ -231,9 +520,29 @@ struct NotInRangeVerifier : public T { static_assert(!std::is_base_of_v, "T cannot be TableVerifier"); static_assert(!std::is_base_of_v, "T cannot be VectorVerifier"); + /** + * Constructs a InRangeVerifier that checks whether the incoming value is of the + * correct type and whether the value is less then \p lower and greater than \upper. + * \param lower The (exclusive) lower limit of the range + * \param upper The (exclusive) upper limit of the range + * \pre \p lower must be smaller or equal to \p upper + */ NotInRangeVerifier(typename T::Type lower, typename T::Type upper); - TestResult operator()(const ghoul::Dictionary& dict, + /** + * Tests whether the \p key exists in the \p dictionary, whether it has the correct + * type by invoking the template parameter \c T, and then tests if the \p key's value + * is outside the lower and upper limits (both exclusive) that were passed to the + * constructor. + * \param dictionary The ghoul::Dictionary that contains the \p key + * \param key The key that is contained in the \p dictionary and whose value is tested + * \return A TestResult containing the results of the specification testing. If the + * \p key%'s value has the wrong type, it will be added to the TestResult's offense + * list with the reason TestResult::Offense::Reason::WrongType; if the value is greater + * or equal to the lower limit and less or equal to the upper limit, it will be added + * with the reason TestResult::Offense::Verification instead. + */ + TestResult operator()(const ghoul::Dictionary& dictionary, const std::string& key) const override; std::string documentation() const override; @@ -242,92 +551,217 @@ struct NotInRangeVerifier : public T { typename T::Type upper; }; -// Misc Verifiers +//---------------------------------------------------------------------------------------- +// Misc verifiers +//---------------------------------------------------------------------------------------- + +/** + * This Verifier only checks for the correct type of the incoming value. If the + * documentation is requested, it will return an additional string that is the annotation. + * This can be used to specify further conditions that are hard (or impossible) to codify, + * but the user should be notified about. This, for example, can be that used to notify + * the user that the parameter should be a file of a specific type. + */ template struct AnnotationVerifier : public T { + /** + * Constructs an AnnotationVerifier that contains the passed \p annotation which is + * passed to the user when a documentation is requested. + * \param annotation The annotation that is stored and returned to the user when it + * is requested. + * \pre annotation must not be empty + */ AnnotationVerifier(std::string annotation); std::string documentation() const override; + /// The annotation that is returned to the user in the documentation std::string annotation; }; -// Boolean Verifiers +//---------------------------------------------------------------------------------------- +// Misc verifiers +//---------------------------------------------------------------------------------------- +/** + * This Verifier takes two Verifiers and performs a boolean \c and operation on their + * results. In essence, a value only passes this Verifier if it passes both Verifier%s + * that are passed in the constructor. Opposed to the C++ && + * operator, the AndVerifier does not perform any short-circut evaluation. + */ struct AndVerifier : public Verifier { - AndVerifier(Verifier* a, Verifier* b); + /** + * Constructs an AndVerifier with two Verifiers which must be cleared by incoming + * values in order to pass this Verifier. + * \param lhs The first Verifier that is to be tested + * \param rhs The second Verifier that is to be tested + * \pre lhs must not be nullptr + * \pre rhs must not be nullptr + */ + AndVerifier(Verifier* lhs, Verifier* rhs); - TestResult operator()(const ghoul::Dictionary& dict, + /** + * Checks whether the \p dictionary contains the \p key and whether this key passes + * both Verifier%'s that were passed in the constructor. If the value fails either + * of the two Verifiers, it is only added once to the TestResult::offenses list with + * a reason of TestResult::Offense::Reason::Verification. + * \param dictionary The ghoul::Dictionary that is to be tested + * \param key The key contained in \p dictionary that is to be tested + * \return A TestResult object that contains the test results. If the value fails + * either of the two Verifiers, TestResult::success is \c false and the + * TestResult::offenses list contains \p with a reason of + * TestResult::Offense::Reason::Verification. If \p key%'s value passes both + * Verifier%s, the result's TestResult::success is \c true and the + * TestResult::offenses is empty. + */ + TestResult operator()(const ghoul::Dictionary& dictionary, const std::string& key) const override; std::string type() const override; std::string documentation() const override; - std::shared_ptr a; - std::shared_ptr b; + /// The first Verifier that incoming values are tested against + std::shared_ptr lhs; + /// The second Verifier that incoming values are tested against + std::shared_ptr rhs; }; +/** +* This Verifier takes two Verifiers and performs a boolean \c or operation on their +* results. In essence, a value only passes this Verifier if it passes either of the two +* Verifier%s that are passed in the constructor. Opposed to the C++ +* || operator, the OrVerifier does not perform any short-circut evaluation. +*/ struct OrVerifier : public Verifier { - OrVerifier(Verifier* a, Verifier* b); + /** + * Constructs an OrVerifier with two Verifiers, either of which must be cleared by + * incoming values in order to pass this Verifier. + * \param lhs The first Verifier that is to be tested + * \param rhs The second Verifier that is to be tested + * \pre lhs must not be nullptr + * \pre rhs must not be nullptr + */ + OrVerifier(Verifier* lhs, Verifier* rhs); + /** + * Checks whether the \p dictionary contains the \p key and whether this key passes + * either of the two Verifier%'s that were passed in the constructor. If the value + * fails both Verifiers, it is added to the TestResult::offenses list with a reason of + * TestResult::Offense::Reason::Verification. + * \param dictionary The ghoul::Dictionary that is to be tested + * \param key The key contained in \p dictionary that is to be tested + * \return A TestResult object that contains the test results. If the value fails + * both Verifiers, TestResult::success is \c false and the TestResult::offenses list + * contains \p with a reason of TestResult::Offense::Reason::Verification. If \p key%'s + * value passes either of the two Verifier%s, the result's TestResult::success is + * \c true and the TestResult::offenses is empty. + */ TestResult operator()(const ghoul::Dictionary& dict, const std::string& key) const override; std::string type() const override; std::string documentation() const override; - std::shared_ptr a; - std::shared_ptr b; + /// The first Verifier that incoming values are tested against + std::shared_ptr lhs; + /// The second Verifier that incoming values are tested against + std::shared_ptr rhs; }; +/// A short-hand definition for a Verifier checking for glm::bvec2 using BoolVector2Verifier = Vector2Verifier; +/// A short-hand definition for a Verifier checking for glm::ivec2 using IntVector2Verifier = Vector2Verifier; +/// A short-hand definition for a Verifier checking for glm::dvec2 using DoubleVector2Verifier = Vector2Verifier; +/// A short-hand definition for a Verifier checking for glm::bvec3 using BoolVector3Verifier = Vector3Verifier; +/// A short-hand definition for a Verifier checking for glm::ivec3 using IntVector3Verifier = Vector3Verifier; +/// A short-hand definition for a Verifier checking for glm::dvec3 using DoubleVector3Verifier = Vector3Verifier; +/// A short-hand definition for a Verifier checking for glm::bvec4 using BoolVector4Verifier = Vector4Verifier; +/// A short-hand definition for a Verifier checking for glm::ivec4 using IntVector4Verifier = Vector4Verifier; +/// A short-hand definition for a Verifier checking for glm::dvec4 using DoubleVector4Verifier = Vector4Verifier; +/// A short-hand definition for a LessVerifier with a type check for \c int using IntLessVerifier = LessVerifier; +/// A short-hand definition for a LessVerifier with a type check for \c double using DoubleLessVerifier = LessVerifier; +/// A short-hand definition for a LessEqualVerifier with a type check for \c int using IntLessEqualVerifier = LessEqualVerifier; +/// A short-hand definition for a LessEqualVerifier with a type check for \c double using DoubleLessEqualVerifier = LessEqualVerifier; +/// A short-hand definition for a GreaterVerifier with a type check for \c int using IntGreaterVerifier = GreaterVerifier; +/// A short-hand definition for a GreaterVerifier with a type check for \c double using DoubleGreaterVerifier = GreaterVerifier; +/// A short-hand definition for a GreaterEqualVerifier with a type check for \c int using IntGreaterEqualVerifier = GreaterEqualVerifier; +/// A short-hand definition for a GreaterEqualVerifier with a type check for \c double using DoubleGreaterEqualVerifier = GreaterEqualVerifier; +/// A short-hand definition for a EqualVerifier with a type check for \c bool using BoolEqualVerifier = EqualVerifier; +/// A short-hand definition for a EqualVerifier with a type check for \c int using IntEqualVerifier = EqualVerifier; +/// A short-hand definition for a EqualVerifier with a type check for \c double using DoubleEqualVerifier = EqualVerifier; +/// A short-hand definition for a EqualVerifier with a type check for \c string using StringEqualVerifier = EqualVerifier; +/// A short-hand definition for a UnequalVerifier with a type check for \c bool using BoolUnequalVerifier = UnequalVerifier; +/// A short-hand definition for a UnequalVerifier with a type check for \c int using IntUnequalVerifier = UnequalVerifier; +/// A short-hand definition for a UnequalVerifier with a type check for \c double using DoubleUnequalVerifier = UnequalVerifier; +/// A short-hand definition for a UnequalVerifier with a type check for \c string using StringUnequalVerifier = UnequalVerifier; +/// A short-hand definition for a InListVerifier with a type check for \c bool using BoolInListVerifier = InListVerifier; +/// A short-hand definition for a InListVerifier with a type check for \c int using IntInListVerifier = InListVerifier; +/// A short-hand definition for a InListVerifier with a type check for \c double using DoubleInListVerifier = InListVerifier; +/// A short-hand definition for a InListVerifier with a type check for \c string using StringInListVerifier = InListVerifier; +/// A short-hand definition for a NotInListVerifier with a type check for \c bool using BoolNotInListVerifier = NotInListVerifier; +/// A short-hand definition for a NotInListVerifier with a type check for \c int using IntNotInListVerifier = NotInListVerifier; +/// A short-hand definition for a NotInListVerifier with a type check for \c double using DoubleNotInListVerifier = NotInListVerifier; +/// A short-hand definition for a NotInListVerifier with a type check for \c string using StringNotInListVerifier = NotInListVerifier; +/// A short-hand definition for a InRangeVerifier with a type check for \c int using IntInRangeVerifier = InRangeVerifier; +/// A short-hand definition for a InRangeVerifier with a type check for \c double using DoubleInRangeVerifier = InRangeVerifier; +/// A short-hand definition for a NotInRangeVerifier with a type check for \c int using IntNotInRangeVerifier = NotInRangeVerifier; +/// A short-hand definition for a NotInRangeVerifier with a type check for \c double using DoubleNotInRangeVerifier = NotInRangeVerifier; +/// A short-hand definition for a AnnotationVerifier with a type check for \c bool using BoolAnnotationVerifier = AnnotationVerifier; +/// A short-hand definition for a AnnotationVerifier with a type check for \c int using IntAnnotationVerifier = AnnotationVerifier; +/// A short-hand definition for a AnnotationVerifier with a type check for \c double using DoubleAnnotationVerifier = AnnotationVerifier; +/// A short-hand definition for a AnnotationVerifier with a type check for \c string using StringAnnotationVerifier = AnnotationVerifier; +/// A short-hand definition for a AnnotationVerifier with a type check for +/// ghoul::Dictionary using TableAnnotationVerifier = AnnotationVerifier; +// Definitions of external templates that are instantiated in the cpp file +// This cuts down the compilation times as almost all of the possible template types do +// not need to be instantiated multiple times extern template struct Vector2Verifier; extern template struct Vector2Verifier; extern template struct Vector2Verifier; diff --git a/include/openspace/documentation/verifier.inl b/include/openspace/documentation/verifier.inl index f3256446b3..f868c8432a 100644 --- a/include/openspace/documentation/verifier.inl +++ b/include/openspace/documentation/verifier.inl @@ -25,7 +25,7 @@ #include namespace std { -std::string to_string(std::string value); + std::string to_string(std::string value); } namespace openspace { @@ -35,17 +35,22 @@ template TestResult TemplateVerifier::operator()(const ghoul::Dictionary& dict, const std::string& key) const { - if (dict.hasKey(key)) { - if (dict.hasValue(key)) { - return{ true, {} }; + if (dict.hasKeyAndValue(key)) { + return { true, {} }; + } + else { + if (dict.hasKey(key)) { + return { false, { { key, TestResult::Offense::Reason::MissingKey } } }; } else { return { false, { { key, TestResult::Offense::Reason::WrongType } } }; } } - else { - return { false, { { key, TestResult::Offense::Reason::MissingKey } } }; - } +} + +template +std::string TemplateVerifier::documentation() const { + return "Type testing of '" + type() + "'"; } template @@ -69,18 +74,18 @@ std::string Vector4Verifier::type() const { return "Vector4<"s + typeid(T).name() + ">"; } -template -OperatorVerifier::OperatorVerifier(typename T::Type value) +template +OperatorVerifier::OperatorVerifier(typename T::Type value) : value(std::move(value)) {} -template -TestResult OperatorVerifier::operator()(const ghoul::Dictionary& dict, - const std::string& key) const +template +TestResult OperatorVerifier::operator()(const ghoul::Dictionary& dict, + const std::string& key) const { TestResult res = T::operator()(dict, key); if (res.success) { - if (Op()(dict.value(key), value)) { + if (Operator()(dict.value(key), value)) { return { true, {} }; } else { @@ -154,7 +159,11 @@ std::string InListVerifier::documentation() const { std::string result = "In list { "; std::stringstream s; - std::copy(values.begin(), values.end(), std::ostream_iterator(s, ",")); + std::copy( + values.begin(), + values.end(), + std::ostream_iterator(s, ",") + ); std::string joined = s.str(); // We need to remove a trailing ',' at the end of the string @@ -196,13 +205,16 @@ std::string NotInListVerifier::documentation() const { std::string result = "Not in list { "; std::stringstream s; - std::copy(values.begin(), values.end(), std::ostream_iterator(s, ",")); + std::copy( + values.begin(), + values.end(), + std::ostream_iterator(s, ",") + ); std::string joined = s.str(); // We need to remove a trailing ',' at the end of the string result += joined.substr(0, joined.size() - 1); - result += " }"; return result; } @@ -212,10 +224,9 @@ InRangeVerifier::InRangeVerifier(typename T::Type lower, typename T::Type upp : lower(std::move(lower)) , upper(std::move(upper)) { - ghoul_assert(lower <= upper, "Lower value must be smaller or equal to upper value"); + ghoul_assert(lower <= upper, "lower must be smaller or equal to upper"); } - template TestResult InRangeVerifier::operator()(const ghoul::Dictionary& dict, const std::string& key) const @@ -247,7 +258,7 @@ NotInRangeVerifier::NotInRangeVerifier(typename T::Type lower, typename T::Ty : lower(std::move(lower)) , upper(std::move(upper)) { - ghoul_assert(lower <= upper, "Lower value must be smaller or equal to upper value"); + ghoul_assert(lower <= upper, "lower must be smaller or equal to upper"); } template @@ -279,8 +290,9 @@ std::string NotInRangeVerifier::documentation() const { template AnnotationVerifier::AnnotationVerifier(std::string annotation) : annotation(std::move(annotation)) -{} - +{ + ghoul_assert(!this->annotation.empty(), "Annotation must not be empty"); +} template std::string AnnotationVerifier::documentation() const { diff --git a/include/openspace/scene/scene.h b/include/openspace/scene/scene.h index 622ef1f6e1..0e748a2f65 100644 --- a/include/openspace/scene/scene.h +++ b/include/openspace/scene/scene.h @@ -119,7 +119,7 @@ public: */ static scripting::LuaLibrary luaLibrary(); - static Documentation Documentation(); + static documentation::Documentation Documentation(); private: bool loadSceneInternal(const std::string& sceneDescriptionFilePath); diff --git a/include/openspace/scene/scenegraphnode.h b/include/openspace/scene/scenegraphnode.h index 1a08eeb54a..a7a3c4cac7 100644 --- a/include/openspace/scene/scenegraphnode.h +++ b/include/openspace/scene/scenegraphnode.h @@ -108,7 +108,7 @@ public: _ephemeris = eph; } - static Documentation Documentation(); + static documentation::Documentation Documentation(); private: bool sphereInsideFrustum(const psc& s_pos, const PowerScaledScalar& s_rad, const Camera* camera); diff --git a/modules/toyvolume/toyvolumemodule.cpp b/modules/toyvolume/toyvolumemodule.cpp index 77b65bf4ed..f700830085 100644 --- a/modules/toyvolume/toyvolumemodule.cpp +++ b/modules/toyvolume/toyvolumemodule.cpp @@ -24,7 +24,6 @@ #include -#include #include #include diff --git a/src/documentation/documentation.cpp b/src/documentation/documentation.cpp index 9e223c4786..1c6aac2846 100644 --- a/src/documentation/documentation.cpp +++ b/src/documentation/documentation.cpp @@ -28,9 +28,7 @@ #include namespace { - const std::string Wildcard = "*"; - - // Structure used to make offences unique + // Structure used to make offenses unique struct OffenseCompare { using Offense = openspace::documentation::TestResult::Offense; bool operator()(const Offense& lhs, const Offense& rhs) const @@ -47,6 +45,8 @@ namespace { }; } // namespace +// Unfortunately, the standard library does not contain a no-op for the to_string method +// so we have to include one ourselves namespace std { std::string to_string(std::string value) { return value; @@ -56,62 +56,67 @@ std::string to_string(std::string value) { namespace openspace { namespace documentation { -SpecificationError::SpecificationError(TestResult result, std::string component) +const std::string DocumentationEntry::Wildcard = "*"; + +SpecificationError::SpecificationError(TestResult res, std::string component) : ghoul::RuntimeError("Error in specification", std::move(component)) - , result(std::move(result)) {} + , result(std::move(res)) +{ + ghoul_assert(!result.success, "Result's success must be false"); +} - -DocumentationEntry::DocumentationEntry(std::string key, Verifier* t, std::string doc, - Optional optional) - : key(std::move(key)) - , verifier(std::move(t)) +DocumentationEntry::DocumentationEntry(std::string k, std::shared_ptr v, + std::string doc, Optional opt) + : key(std::move(k)) + , verifier(std::move(v)) , documentation(std::move(doc)) - , optional(optional) {} + , optional(opt) +{ + ghoul_assert(!key.empty(), "Key must not be empty"); + ghoul_assert(verifier, "Verifier must not be nullptr"); +} -Documentation::Documentation(std::string name, DocumentationEntries entries, Exhaustive exhaustive) - : name(std::move(name)) - , entries(std::move(entries)) - , exhaustive(std::move(exhaustive)) +DocumentationEntry::DocumentationEntry(std::string key, Verifier* v, std::string doc, + Optional optional) + : DocumentationEntry(std::move(key), std::shared_ptr(v), std::move(doc), + optional) {} -Documentation::Documentation(DocumentationEntries entries) - : Documentation("", std::move(entries)) {} +Documentation::Documentation(std::string n, DocumentationEntries entries, Exhaustive exh) + : name(std::move(n)) + , entries(std::move(entries)) + , exhaustive(std::move(exh)) +{} -TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& dictionary) { +TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& dict) { TestResult result; result.success = true; + auto applyVerifier = [dict, &result](Verifier& verifier, const std::string& key) { + TestResult res = verifier(dict, key); + if (!res.success) { + result.success = false; + result.offenses.insert( + result.offenses.end(), + res.offenses.begin(), + res.offenses.end() + ); + } + }; + for (const auto& p : d.entries) { - if (p.key == Wildcard) { - for (const std::string& key : dictionary.keys()) { - Verifier& verifier = *(p.verifier); - TestResult res = verifier(dictionary, key); - if (!res.success) { - result.success = false; - result.offenses.insert( - result.offenses.end(), - res.offenses.begin(), - res.offenses.end() - ); - } + if (p.key == DocumentationEntry::Wildcard) { + for (const std::string& key : dict.keys()) { + applyVerifier(*(p.verifier), key); } } else { - if (p.optional && !dictionary.hasKey(p.key)) { + if (p.optional && !dict.hasKey(p.key)) { // If the key is optional and it doesn't exist, we don't need to check it // if the key exists, it has to be correct, however continue; } - Verifier& verifier = *(p.verifier); - TestResult res = verifier(dictionary, p.key); - if (!res.success) { - result.success = false; - result.offenses.insert( - result.offenses.end(), - res.offenses.begin(), - res.offenses.end() - ); - } + applyVerifier(*(p.verifier), p.key); } } @@ -119,12 +124,12 @@ TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& di // If the documentation is exhaustive, we have to check if there are extra values // in the table that are not covered by the Documentation - for (const std::string& key : dictionary.keys()) { + for (const std::string& key : dict.keys()) { auto it = std::find_if( d.entries.begin(), d.entries.end(), [&key](const DocumentationEntry& entry) { - if (entry.key == Wildcard) { + if (entry.key == DocumentationEntry::Wildcard) { return true; } else { @@ -154,16 +159,11 @@ TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& di return result; } -void testSpecificationAndThrow(const Documentation& doc, - const ghoul::Dictionary& dictionary, std::string component) - +void testSpecificationAndThrow(const Documentation& doc, const ghoul::Dictionary& dict, + std::string component) { // Perform testing against the documentation/specification - using namespace openspace::documentation; - TestResult testResult = testSpecification( - doc, - dictionary - ); + TestResult testResult = testSpecification(doc, dict); if (!testResult.success) { throw SpecificationError(std::move(testResult), std::move(component)); } diff --git a/src/documentation/documentationengine.cpp b/src/documentation/documentationengine.cpp index 2489730b41..3960467412 100644 --- a/src/documentation/documentationengine.cpp +++ b/src/documentation/documentationengine.cpp @@ -59,7 +59,7 @@ std::string generateTextDocumentation(const Documentation& d, int& indentLevel) if (tv) { // We have a TableVerifier, so we need to recurse ++indentLevel; - result += generateTextDocumentation(tv->doc, indentLevel); + result += generateTextDocumentation({ "", tv->documentations }, indentLevel); result = result.substr(0, result.size() - 2); --indentLevel; } @@ -89,8 +89,9 @@ std::string generateJsonDocumentation(const Documentation& d) { result << "\"type\": \"" << p.verifier->type() << "\","; TableVerifier* tv = dynamic_cast(p.verifier.get()); if (tv) { + std::string json = generateJsonDocumentation({ "", tv->documentations }); // We have a TableVerifier, so we need to recurse - result << "\"restrictions\": " << generateJsonDocumentation(tv->doc) << ","; + result << "\"restrictions\": " << json << ","; } else { result << "\"restrictions\": \"" << p.verifier->documentation() << "\","; @@ -131,7 +132,7 @@ std::string generateHtmlDocumentation(const Documentation& d) { << "\t\t\n" << "\t\n" << "\t\n" - << generateHtmlDocumentation(tv->doc) + << generateHtmlDocumentation({ "", tv->documentations }) << "\t\n" << "\n" << "\n"; diff --git a/src/documentation/verifier.cpp b/src/documentation/verifier.cpp index 4e35f343e8..9af9f7b22a 100644 --- a/src/documentation/verifier.cpp +++ b/src/documentation/verifier.cpp @@ -27,6 +27,8 @@ namespace openspace { namespace documentation { +// The explicit template instantiations for many of the commonly used template values +// This cuts down on the compilation time by only compiling these once template struct Vector2Verifier; template struct Vector2Verifier; template struct Vector2Verifier; @@ -74,10 +76,6 @@ template struct AnnotationVerifier; template struct AnnotationVerifier; template struct AnnotationVerifier; -std::string Verifier::documentation() const { - return ""; -} - std::string BoolVerifier::type() const { return "Boolean"; } @@ -87,9 +85,10 @@ std::string DoubleVerifier::type() const { } TestResult IntVerifier::operator()(const ghoul::Dictionary & dict, - const std::string & key) const + const std::string & key) const { if (dict.hasKeyAndValue(key)) { + // We we have a key and the value is int, we are done return { true, {} }; } else { @@ -126,7 +125,7 @@ std::string StringVerifier::type() const { } TableVerifier::TableVerifier(std::vector d, Exhaustive exhaustive) - : doc(std::move(d)) + : documentations(std::move(d)) , exhaustive(std::move(exhaustive)) {} @@ -135,7 +134,7 @@ TestResult TableVerifier::operator()(const ghoul::Dictionary& dict, { if (dict.hasKeyAndValue(key)) { ghoul::Dictionary d = dict.value(key); - TestResult res = testSpecification({ "", doc, exhaustive }, d); + TestResult res = testSpecification({ "", documentations, exhaustive }, d); for (TestResult::Offense& s : res.offenses) { s.offender = key + "." + s.offender; @@ -158,20 +157,21 @@ std::string TableVerifier::type() const { return "Table"; } -AndVerifier::AndVerifier(Verifier* a, Verifier* b) - : a(a) - , b(b) +AndVerifier::AndVerifier(Verifier* lhs, Verifier* rhs) + : lhs(lhs) + , rhs(rhs) { - ghoul_assert(a->type() == b->type(), "Cannot use AndVerifier with different types"); + ghoul_assert(lhs, "lhs must not be nullptr"); + ghoul_assert(rhs, "rhs must not be nullptr"); } TestResult AndVerifier::operator()(const ghoul::Dictionary& dict, const std::string& key) const { - TestResult resA = a->operator()(dict, key); - TestResult resB = b->operator()(dict, key); + TestResult resLhs = lhs->operator()(dict, key); + TestResult resRhs = rhs->operator()(dict, key); - if (resA.success && resB.success) { + if (resLhs.success && resRhs.success) { return { true, {} }; } else { @@ -180,23 +180,30 @@ TestResult AndVerifier::operator()(const ghoul::Dictionary& dict, } std::string AndVerifier::type() const { - // It does not matter which type we choose as they both have to be the same - return a->type(); + if (lhs->type() != rhs->type()) { + return lhs->type() + " and " + rhs->type(); + } + else { + return lhs->type(); + } } std::string AndVerifier::documentation() const { - return a->documentation() + " and " + b->documentation(); + return lhs->documentation() + " and " + rhs->documentation(); } -OrVerifier::OrVerifier(Verifier* a, Verifier* b) - : a(a) - , b(b) -{} +OrVerifier::OrVerifier(Verifier* lhs, Verifier* rhs) + : lhs(lhs) + , rhs(rhs) +{ + ghoul_assert(lhs, "lhs must not be nullptr"); + ghoul_assert(rhs, "rhs must not be nullptr"); +} TestResult OrVerifier::operator()(const ghoul::Dictionary& dict, const std::string& key) const { - TestResult resA = a->operator()(dict, key); - TestResult resB = b->operator()(dict, key); + TestResult resA = lhs->operator()(dict, key); + TestResult resB = rhs->operator()(dict, key); if (resA.success || resB.success) { return { true, {} }; @@ -207,16 +214,16 @@ TestResult OrVerifier::operator()(const ghoul::Dictionary& dict, } std::string OrVerifier::type() const { - if (a->type() != b->type()) { - return a->type() + " or " + b->type(); + if (lhs->type() != rhs->type()) { + return lhs->type() + " or " + rhs->type(); } else { - return a->type(); + return lhs->type(); } } std::string OrVerifier::documentation() const { - return a->documentation() + " or " + b->documentation(); + return lhs->documentation() + " or " + rhs->documentation(); } diff --git a/tests/test_documentation.inl b/tests/test_documentation.inl index a009329d32..7673955d79 100644 --- a/tests/test_documentation.inl +++ b/tests/test_documentation.inl @@ -735,6 +735,85 @@ TEST_F(DocumentationTest, NestedExhaustive) { EXPECT_EQ(TestResult::Offense::Reason::ExtraKey, negativeRes.offenses[1].reason); } +TEST_F(DocumentationTest, EmptyEntriesNonExhaustive) { + using namespace openspace::documentation; + + Documentation doc { + "Test", + {} + }; + + ghoul::Dictionary positive {}; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenses.size()); + + ghoul::Dictionary positive2 { + { "a", 1 } + }; + positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenses.size()); +} + +TEST_F(DocumentationTest, EmptyEntriesExhaustive) { + using namespace openspace::documentation; + + Documentation doc { + "Test", + {}, + Exhaustive::Yes + }; + + ghoul::Dictionary positive {}; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenses.size()); + + ghoul::Dictionary negative { + { "a", 1 } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("a", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::ExtraKey, negativeRes.offenses[0].reason); +} + +TEST_F(DocumentationTest, EmptyNestedExhaustive) { + using namespace openspace::documentation; + + Documentation doc { + "Test", + {{ + "Table", + new TableVerifier( + { + }, + Exhaustive::Yes + ) + }} + }; + + ghoul::Dictionary positive { + { "Table", ghoul::Dictionary() } + }; + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenses.size()); + + ghoul::Dictionary negative { + { "Table", ghoul::Dictionary{ { "a", 1 }}} + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Table.a", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::ExtraKey, negativeRes.offenses[0].reason); +} + + + TEST_F(DocumentationTest, LessInt) { using namespace openspace::documentation; @@ -1725,7 +1804,7 @@ TEST_F(DocumentationTest, Wildcard) { Documentation doc { "Test", - {{ "*", new IntVerifier }} + {{ DocumentationEntry::Wildcard, new IntVerifier }} }; ghoul::Dictionary positive { @@ -1783,7 +1862,7 @@ TEST_F(DocumentationTest, WildcardMixed) { Documentation doc { "Test", { - { "*", new IntVerifier }, + { DocumentationEntry::Wildcard, new IntVerifier }, { "b", new IntGreaterVerifier(5) } } }; @@ -2229,3 +2308,121 @@ TEST_F(DocumentationTest, DoubleVector4Verifier) { EXPECT_EQ("a", negativeRes.offenses[0].offender); EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); } + +TEST_F(DocumentationTest, VerifierTypePostConditions) { + using namespace openspace::documentation; + using namespace std::string_literals; + + EXPECT_NE("", BoolVerifier().type()); + EXPECT_NE("", DoubleVerifier().type()); + EXPECT_NE("", IntVerifier().type()); + EXPECT_NE("", StringVerifier().type()); + EXPECT_NE("", TableVerifier().type()); + + EXPECT_NE("", BoolVector2Verifier().type()); + EXPECT_NE("", IntVector2Verifier().type()); + EXPECT_NE("", DoubleVector2Verifier().type()); + EXPECT_NE("", BoolVector3Verifier().type()); + EXPECT_NE("", IntVector3Verifier().type()); + EXPECT_NE("", DoubleVector3Verifier().type()); + EXPECT_NE("", BoolVector4Verifier().type()); + EXPECT_NE("", IntVector4Verifier().type()); + EXPECT_NE("", DoubleVector4Verifier().type()); + + EXPECT_NE("", IntLessVerifier(0).type()); + EXPECT_NE("", DoubleLessVerifier(0.0).type()); + EXPECT_NE("", IntLessEqualVerifier(0).type()); + EXPECT_NE("", DoubleLessEqualVerifier(0.0).type()); + EXPECT_NE("", IntGreaterVerifier(0).type()); + EXPECT_NE("", DoubleGreaterVerifier(0.0).type()); + EXPECT_NE("", IntGreaterEqualVerifier(0).type()); + EXPECT_NE("", DoubleGreaterEqualVerifier(0.0).type()); + + EXPECT_NE("", BoolEqualVerifier(true).type()); + EXPECT_NE("", IntEqualVerifier(0).type()); + EXPECT_NE("", DoubleEqualVerifier(0.0).type()); + EXPECT_NE("", StringEqualVerifier(""s).type()); + EXPECT_NE("", BoolUnequalVerifier(true).type()); + EXPECT_NE("", IntUnequalVerifier(0).type()); + EXPECT_NE("", DoubleUnequalVerifier(0.0).type()); + EXPECT_NE("", StringUnequalVerifier(""s).type()); + + EXPECT_NE("", BoolInListVerifier({ true }).type()); + EXPECT_NE("", IntInListVerifier({ 0 }).type()); + EXPECT_NE("", DoubleInListVerifier({ 0.0 }).type()); + EXPECT_NE("", StringInListVerifier({ ""s }).type()); + EXPECT_NE("", BoolNotInListVerifier({ true }).type()); + EXPECT_NE("", IntNotInListVerifier({ 0 }).type()); + EXPECT_NE("", DoubleNotInListVerifier({ 0.0 }).type()); + EXPECT_NE("", StringNotInListVerifier({ ""s }).type()); + + EXPECT_NE("", IntInRangeVerifier({ 0, 1 }).type()); + EXPECT_NE("", DoubleInRangeVerifier({ 0.0, 1.0 }).type()); + EXPECT_NE("", IntNotInRangeVerifier({ 0, 1 }).type()); + EXPECT_NE("", DoubleNotInRangeVerifier({ 0.0, 1.0 }).type()); + + EXPECT_NE("", BoolAnnotationVerifier("Annotation"s).type()); + EXPECT_NE("", IntAnnotationVerifier("Annotation"s).type()); + EXPECT_NE("", DoubleAnnotationVerifier("Annotation"s).type()); + EXPECT_NE("", StringAnnotationVerifier("Annotation"s).type()); + EXPECT_NE("", TableAnnotationVerifier("Annotation"s).type()); +} + +TEST_F(DocumentationTest, VerifierDocumentationPostConditions) { + using namespace openspace::documentation; + using namespace std::string_literals; + + EXPECT_NE("", BoolVerifier().documentation()); + EXPECT_NE("", DoubleVerifier().documentation()); + EXPECT_NE("", IntVerifier().documentation()); + EXPECT_NE("", StringVerifier().documentation()); + EXPECT_NE("", TableVerifier().documentation()); + + EXPECT_NE("", BoolVector2Verifier().documentation()); + EXPECT_NE("", IntVector2Verifier().documentation()); + EXPECT_NE("", DoubleVector2Verifier().documentation()); + EXPECT_NE("", BoolVector3Verifier().documentation()); + EXPECT_NE("", IntVector3Verifier().documentation()); + EXPECT_NE("", DoubleVector3Verifier().documentation()); + EXPECT_NE("", BoolVector4Verifier().documentation()); + EXPECT_NE("", IntVector4Verifier().documentation()); + EXPECT_NE("", DoubleVector4Verifier().documentation()); + + EXPECT_NE("", IntLessVerifier(0).documentation()); + EXPECT_NE("", DoubleLessVerifier(0.0).documentation()); + EXPECT_NE("", IntLessEqualVerifier(0).documentation()); + EXPECT_NE("", DoubleLessEqualVerifier(0.0).documentation()); + EXPECT_NE("", IntGreaterVerifier(0).documentation()); + EXPECT_NE("", DoubleGreaterVerifier(0.0).documentation()); + EXPECT_NE("", IntGreaterEqualVerifier(0).documentation()); + EXPECT_NE("", DoubleGreaterEqualVerifier(0.0).documentation()); + + EXPECT_NE("", BoolEqualVerifier(true).documentation()); + EXPECT_NE("", IntEqualVerifier(0).documentation()); + EXPECT_NE("", DoubleEqualVerifier(0.0).documentation()); + EXPECT_NE("", StringEqualVerifier(""s).documentation()); + EXPECT_NE("", BoolUnequalVerifier(true).documentation()); + EXPECT_NE("", IntUnequalVerifier(0).documentation()); + EXPECT_NE("", DoubleUnequalVerifier(0.0).documentation()); + EXPECT_NE("", StringUnequalVerifier(""s).documentation()); + + EXPECT_NE("", BoolInListVerifier({ true }).documentation()); + EXPECT_NE("", IntInListVerifier({ 0 }).documentation()); + EXPECT_NE("", DoubleInListVerifier({ 0.0 }).documentation()); + EXPECT_NE("", StringInListVerifier({ ""s }).documentation()); + EXPECT_NE("", BoolNotInListVerifier({ true }).documentation()); + EXPECT_NE("", IntNotInListVerifier({ 0 }).documentation()); + EXPECT_NE("", DoubleNotInListVerifier({ 0.0 }).documentation()); + EXPECT_NE("", StringNotInListVerifier({ ""s }).documentation()); + + EXPECT_NE("", IntInRangeVerifier({ 0, 1 }).documentation()); + EXPECT_NE("", DoubleInRangeVerifier({ 0.0, 1.0 }).documentation()); + EXPECT_NE("", IntNotInRangeVerifier({ 0, 1 }).documentation()); + EXPECT_NE("", DoubleNotInRangeVerifier({ 0.0, 1.0 }).documentation()); + + EXPECT_NE("", BoolAnnotationVerifier("Annotation"s).documentation()); + EXPECT_NE("", IntAnnotationVerifier("Annotation"s).documentation()); + EXPECT_NE("", DoubleAnnotationVerifier("Annotation"s).documentation()); + EXPECT_NE("", StringAnnotationVerifier("Annotation"s).documentation()); + EXPECT_NE("", TableAnnotationVerifier("Annotation"s).documentation()); +} From 0a13d5430fc555679c1c562c6e1ddbfe4362459e Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Mon, 19 Sep 2016 09:31:34 +0200 Subject: [PATCH 85/92] Make DocumentationEngine into a singleton object Add documentation to DocumentationEngine Add unique identifier to Documentation class (and enforce in DocumentationEngine) --- .../openspace/documentation/documentation.h | 11 ++- .../documentation/documentationengine.h | 39 +++++++++-- include/openspace/engine/openspaceengine.h | 3 - src/documentation/documentation.cpp | 12 +++- src/documentation/documentationengine.cpp | 35 ++++++++-- src/engine/openspaceengine.cpp | 14 ++-- tests/test_documentation.inl | 67 +------------------ 7 files changed, 93 insertions(+), 88 deletions(-) diff --git a/include/openspace/documentation/documentation.h b/include/openspace/documentation/documentation.h index 684e25b7fa..25b770df8d 100644 --- a/include/openspace/documentation/documentation.h +++ b/include/openspace/documentation/documentation.h @@ -206,16 +206,25 @@ struct Documentation { /** * Creates a Documentation with a human-readable \p name and a list of \p entries. * \param name The human-readable name of this Documentation + * \param id A unique identifier which can be used by applications (or other + * Documentation%s to reference this entry * \param entries A list of DocumentationEntry%s that describe the individual keys for * this entrie Documentation * \param exhaustive Determines whether the \p entries are an exhaustive specification * of the object or whether additional, potentially unused, keys are allowed */ - Documentation(std::string name = "", DocumentationEntries entries = {}, + Documentation(std::string name, std::string id, DocumentationEntries entries = {}, Exhaustive exhaustive = Exhaustive::No); + Documentation(std::string name, DocumentationEntries entries = {}, + Exhaustive exhaustive = Exhaustive::No); + + Documentation(DocumentationEntries entries = {}, Exhaustive exhaustive = Exhaustive::No); + /// The human-readable name of the Documentation std::string name; + /// A unique identifier which can be used to reference this Documentation + std::string id; /// A list of specifications that are describing this Documentation DocumentationEntries entries; /// A flag to say wheter the DocumentationEntries are an exhaustive description diff --git a/include/openspace/documentation/documentationengine.h b/include/openspace/documentation/documentationengine.h index ddc586b9c6..99837e7bb4 100644 --- a/include/openspace/documentation/documentationengine.h +++ b/include/openspace/documentation/documentationengine.h @@ -27,24 +27,55 @@ #include +#include +#include + namespace openspace { namespace documentation { -class DocumentationEngine { +/** + * The DocumentationEngine has the ability to collect all Documentation%s that are + * produced in the application an write them out as a documentation file for human + * consumption. + */ +class DocumentationEngine : public ghoul::Singleton { public: + struct DuplicateDocumentationException : public ghoul::RuntimeError { + DuplicateDocumentationException(Documentation documentation); + Documentation documentation; + }; + + /** + * Write the collected Documentation%s to disk at the \p filename in the specified + * \p type. A new file is created and silently overwritten in the location that + * \p filename is pointed to. + * \param filename The file that is to be created containing all the Documentation + * information. + * \param type The type of documentation that is written. Currently allowed values are + * \c text and \c html + */ void writeDocumentation(const std::string& filename, const std::string& type); - void addDocumentation(Documentation doc); + /** + * Adds the \p documentation to the list of Documentation%s that are written to a + * documentation file with the writeDocumentation method. + * \param documentation The Documentation object that is to be stored for later use + * \throws DuplicateDocumentationException If the \p documentation did not have a + * unique identifier + */ + void addDocumentation(Documentation documentation); + + static DocumentationEngine& ref(); private: + /// The list of all Documentation%s that are stored by the DocumentationEngine std::vector _documentations; - }; } // namespace documentation } // namespace openspace - +#define DocEng (openspace::documentation::DocumentationEngine::ref()) #endif // __DOCUMENTATIONENGINE_H__ diff --git a/include/openspace/engine/openspaceengine.h b/include/openspace/engine/openspaceengine.h index 1ea655b46d..99b6507d78 100644 --- a/include/openspace/engine/openspaceengine.h +++ b/include/openspace/engine/openspaceengine.h @@ -55,7 +55,6 @@ class ModuleEngine; class WindowWrapper; class SettingsEngine; -namespace documentation { class DocumentationEngine; } namespace interaction { class InteractionHandler; } namespace gui { class GUI; } //namespace scripting { class ScriptEngine; } @@ -78,7 +77,6 @@ public: // Guaranteed to return a valid pointer ConfigurationManager& configurationManager(); - documentation::DocumentationEngine& documentationEngine(); interaction::InteractionHandler& interactionHandler(); RenderEngine& renderEngine(); scripting::ScriptEngine& scriptEngine(); @@ -137,7 +135,6 @@ private: // Components std::unique_ptr _configurationManager; - std::unique_ptr _documentationEngine; std::unique_ptr _interactionHandler; std::unique_ptr _renderEngine; std::unique_ptr _scriptEngine; diff --git a/src/documentation/documentation.cpp b/src/documentation/documentation.cpp index 1c6aac2846..5cda43ce74 100644 --- a/src/documentation/documentation.cpp +++ b/src/documentation/documentation.cpp @@ -82,12 +82,22 @@ DocumentationEntry::DocumentationEntry(std::string key, Verifier* v, std::string optional) {} -Documentation::Documentation(std::string n, DocumentationEntries entries, Exhaustive exh) +Documentation::Documentation(std::string n, std::string id, DocumentationEntries entries, + Exhaustive exh) : name(std::move(n)) + , id(std::move(id)) , entries(std::move(entries)) , exhaustive(std::move(exh)) {} +Documentation::Documentation(std::string n, DocumentationEntries entries, Exhaustive exh) + : Documentation(n, "", entries, exh) +{} + +Documentation::Documentation(DocumentationEntries entries, Exhaustive exh) + : Documentation("", "", entries, exh) +{} + TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& dict) { TestResult result; result.success = true; diff --git a/src/documentation/documentationengine.cpp b/src/documentation/documentationengine.cpp index 3960467412..7739d4ef64 100644 --- a/src/documentation/documentationengine.cpp +++ b/src/documentation/documentationengine.cpp @@ -30,9 +30,25 @@ #include +#include + namespace openspace { namespace documentation { +DocumentationEngine::DuplicateDocumentationException::DuplicateDocumentationException( + Documentation documentation) + : ghoul::RuntimeError(fmt::format( + "Duplicate Documentation with name '{}' and id '{}'", + documentation.name, + documentation.id + )) + , documentation(std::move(documentation)) +{} + +DocumentationEngine& DocumentationEngine::ref() { + static DocumentationEngine engine; + return engine; +} std::string generateTextDocumentation(const Documentation& d, int& indentLevel) { using namespace std::string_literals; @@ -59,7 +75,7 @@ std::string generateTextDocumentation(const Documentation& d, int& indentLevel) if (tv) { // We have a TableVerifier, so we need to recurse ++indentLevel; - result += generateTextDocumentation({ "", tv->documentations }, indentLevel); + result += generateTextDocumentation({ "", "", tv->documentations }, indentLevel); result = result.substr(0, result.size() - 2); --indentLevel; } @@ -89,7 +105,7 @@ std::string generateJsonDocumentation(const Documentation& d) { result << "\"type\": \"" << p.verifier->type() << "\","; TableVerifier* tv = dynamic_cast(p.verifier.get()); if (tv) { - std::string json = generateJsonDocumentation({ "", tv->documentations }); + std::string json = generateJsonDocumentation({ "", "", tv->documentations }); // We have a TableVerifier, so we need to recurse result << "\"restrictions\": " << json << ","; } @@ -132,7 +148,7 @@ std::string generateHtmlDocumentation(const Documentation& d) { << "\t\t\n" << "\t\n" << "\t\n" - << generateHtmlDocumentation({ "", tv->documentations }) + << generateHtmlDocumentation({ "", "", tv->documentations }) << "\t\n" << "\n" << "\n"; @@ -220,7 +236,18 @@ void DocumentationEngine::writeDocumentation(const std::string& f, const std::st } void DocumentationEngine::addDocumentation(Documentation doc) { - _documentations.push_back(std::move(doc)); + auto it = std::find_if( + _documentations.begin(), + _documentations.end(), + [doc](const Documentation& d) { return doc.id == d.id; } + ); + + if (it != _documentations.end()) { + throw DuplicateDocumentationException(std::move(doc)); + } + else { + _documentations.push_back(std::move(doc)); + } } } // namespace documentation diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 7eea732086..8186ee8cc8 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -121,7 +121,6 @@ OpenSpaceEngine* OpenSpaceEngine::_engine = nullptr; OpenSpaceEngine::OpenSpaceEngine(std::string programName, std::unique_ptr windowWrapper) : _configurationManager(new ConfigurationManager) - , _documentationEngine(new documentation::DocumentationEngine) , _interactionHandler(new interaction::InteractionHandler) , _renderEngine(new RenderEngine) , _scriptEngine(new scripting::ScriptEngine) @@ -164,8 +163,8 @@ OpenSpaceEngine::OpenSpaceEngine(std::string programName, ghoul::systemcapabilities::SystemCapabilities::initialize(); TransformationManager::initialize(); - _documentationEngine->addDocumentation(ConfigurationManager::Documentation()); - _documentationEngine->addDocumentation(Scene::Documentation()); + DocEng.addDocumentation(ConfigurationManager::Documentation()); + DocEng.addDocumentation(Scene::Documentation()); } OpenSpaceEngine::~OpenSpaceEngine() { @@ -304,7 +303,7 @@ bool OpenSpaceEngine::create(int argc, char** argv, // can be added as well for (OpenSpaceModule* m : _engine->_moduleEngine->modules()) { for (auto&& doc : m->documentations()) { - _engine->_documentationEngine->addDocumentation(doc); + DocEng.addDocumentation(doc); } } @@ -444,7 +443,7 @@ bool OpenSpaceEngine::initialize() { std::string documentationFile; configurationManager().getValue(DocumentationFile, documentationFile); documentationFile = absPath(documentationFile); - _documentationEngine->writeDocumentation(documentationFile, documentationType); + DocEng.writeDocumentation(documentationFile, documentationType); } const std::string FactoryDocumentationType = @@ -1052,11 +1051,6 @@ void OpenSpaceEngine::disableBarrier() { _windowWrapper->setBarrier(false); } -documentation::DocumentationEngine& OpenSpaceEngine::documentationEngine() { - ghoul_assert(_documentationEngine, "DocumentationEngine must not be nullptr"); - return *_documentationEngine; -} - NetworkEngine& OpenSpaceEngine::networkEngine() { ghoul_assert(_networkEngine, "NetworkEngine must not be nullptr"); return *_networkEngine; diff --git a/tests/test_documentation.inl b/tests/test_documentation.inl index 7673955d79..3c78dd3ca3 100644 --- a/tests/test_documentation.inl +++ b/tests/test_documentation.inl @@ -98,7 +98,6 @@ TEST_F(DocumentationTest, InitializerConstructor) { using namespace openspace::documentation; Documentation doc { - "Test", { // Basic Verifiers {"BoolVerifier", new BoolVerifier }, @@ -162,7 +161,6 @@ TEST_F(DocumentationTest, BoolVerifier) { using namespace openspace::documentation; Documentation doc { - "", {{ "Bool", new BoolVerifier }} }; @@ -198,7 +196,6 @@ TEST_F(DocumentationTest, DoubleVerifier) { using namespace openspace::documentation; Documentation doc { - "", {{ "Double", new DoubleVerifier }} }; @@ -234,7 +231,6 @@ TEST_F(DocumentationTest, IntVerifier) { using namespace openspace::documentation; Documentation doc { - "", {{ "Int", new IntVerifier }} }; @@ -277,7 +273,6 @@ TEST_F(DocumentationTest, StringVerifier) { using namespace std::string_literals; Documentation doc { - "Test", {{ "String", new StringVerifier }} }; @@ -311,7 +306,6 @@ TEST_F(DocumentationTest, TableVerifierType) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "Table", new TableVerifier }} }; @@ -346,7 +340,6 @@ TEST_F(DocumentationTest, MixedVerifiers) { using namespace std::string_literals; Documentation doc { - "Test", { { "Bool", new BoolVerifier }, { "Double", new DoubleVerifier }, @@ -401,7 +394,6 @@ TEST_F(DocumentationTest, NestedTables) { using namespace std::string_literals; Documentation doc { - "Test", { { "Outer_Int", new IntVerifier }, { "Outer_Table", new TableVerifier({ @@ -553,7 +545,6 @@ TEST_F(DocumentationTest, Optional) { using namespace openspace::documentation; Documentation doc { - "Test", { { "Bool_Force", new BoolVerifier, "", Optional::No }, { "Bool_Optional", new BoolVerifier, "", Optional::Yes } @@ -607,7 +598,6 @@ TEST_F(DocumentationTest, RequiredInOptional) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "a", new TableVerifier({ @@ -669,7 +659,6 @@ TEST_F(DocumentationTest, Exhaustive) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "Int", new IntVerifier }}, Exhaustive::Yes }; @@ -708,7 +697,6 @@ TEST_F(DocumentationTest, NestedExhaustive) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "Table", new TableVerifier( { { "a", new IntVerifier } }, Exhaustive::Yes @@ -738,10 +726,7 @@ TEST_F(DocumentationTest, NestedExhaustive) { TEST_F(DocumentationTest, EmptyEntriesNonExhaustive) { using namespace openspace::documentation; - Documentation doc { - "Test", - {} - }; + Documentation doc; ghoul::Dictionary positive {}; TestResult positiveRes = testSpecification(doc, positive); @@ -760,7 +745,6 @@ TEST_F(DocumentationTest, EmptyEntriesExhaustive) { using namespace openspace::documentation; Documentation doc { - "Test", {}, Exhaustive::Yes }; @@ -784,7 +768,6 @@ TEST_F(DocumentationTest, EmptyNestedExhaustive) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "Table", new TableVerifier( @@ -818,7 +801,6 @@ TEST_F(DocumentationTest, LessInt) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "Int", new IntLessVerifier(5) }} }; @@ -843,7 +825,6 @@ TEST_F(DocumentationTest, LessDouble) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "Double", new DoubleLessVerifier(5.0) }} }; @@ -868,7 +849,6 @@ TEST_F(DocumentationTest, LessEqualInt) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "Int", new IntLessEqualVerifier(5) }} }; @@ -900,7 +880,6 @@ TEST_F(DocumentationTest, LessEqualDouble) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "Double", new DoubleLessEqualVerifier(5.0) }} }; @@ -932,7 +911,6 @@ TEST_F(DocumentationTest, GreaterInt) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "Int", new IntGreaterVerifier(5) }} }; @@ -957,7 +935,6 @@ TEST_F(DocumentationTest, GreaterDouble) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "Double", new DoubleGreaterVerifier(5.0) }} }; @@ -982,7 +959,6 @@ TEST_F(DocumentationTest, GreaterEqualInt) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "Int", new IntGreaterEqualVerifier(5) }} }; @@ -1014,7 +990,6 @@ TEST_F(DocumentationTest, GreaterEqualDouble) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "Double", new DoubleGreaterEqualVerifier(5.0) }} }; @@ -1046,7 +1021,6 @@ TEST_F(DocumentationTest, EqualBool) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "Bool", new BoolEqualVerifier(true) }} }; @@ -1071,7 +1045,6 @@ TEST_F(DocumentationTest, EqualInt) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "Int", new IntEqualVerifier(1) }} }; @@ -1096,7 +1069,6 @@ TEST_F(DocumentationTest, EqualDouble) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "Double", new DoubleEqualVerifier(1.0) }} }; @@ -1122,7 +1094,6 @@ TEST_F(DocumentationTest, EqualString) { using namespace std::string_literals; Documentation doc { - "Test", {{ "String", new StringEqualVerifier("string"s) }} }; @@ -1147,7 +1118,6 @@ TEST_F(DocumentationTest, UnequalBool) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "Bool", new BoolUnequalVerifier(true) }} }; @@ -1172,7 +1142,6 @@ TEST_F(DocumentationTest, UnequalInt) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "Int", new IntUnequalVerifier(1) }} }; @@ -1197,7 +1166,6 @@ TEST_F(DocumentationTest, UnequalDouble) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "Double", new DoubleUnequalVerifier(1.0) }} }; @@ -1223,7 +1191,6 @@ TEST_F(DocumentationTest, UnequalString) { using namespace std::string_literals; Documentation doc { - "Test", {{ "String", new StringUnequalVerifier("string"s) }} }; @@ -1248,7 +1215,6 @@ TEST_F(DocumentationTest, ListBool) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "Bool" , new BoolInListVerifier({ true }) }} }; @@ -1273,7 +1239,6 @@ TEST_F(DocumentationTest, ListInt) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "Int" , new IntInListVerifier({ 0, 1, 2 }) }} }; @@ -1305,7 +1270,6 @@ TEST_F(DocumentationTest, ListDouble) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "Double" , new DoubleInListVerifier({ 0.0, 1.0, 2.0 }) }} }; @@ -1338,7 +1302,6 @@ TEST_F(DocumentationTest, ListString) { using namespace std::string_literals; Documentation doc { - "Test", {{ "String" , new StringInListVerifier({ "0"s, "1"s, "2"s }) }} }; @@ -1370,7 +1333,6 @@ TEST_F(DocumentationTest, NotListBool) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "Bool" , new BoolNotInListVerifier({ true }) }} }; @@ -1395,7 +1357,6 @@ TEST_F(DocumentationTest, NotListInt) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "Int" , new IntNotInListVerifier({ 0, 1, 2 }) }} }; @@ -1427,7 +1388,6 @@ TEST_F(DocumentationTest, NotListDouble) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "Double" , new DoubleNotInListVerifier({ 0.0, 1.0, 2.0 }) }} }; @@ -1460,7 +1420,6 @@ TEST_F(DocumentationTest, NotListString) { using namespace std::string_literals; Documentation doc { - "Test", {{ "String" , new StringNotInListVerifier({ "0"s, "1"s, "2"s }) }} }; @@ -1492,7 +1451,6 @@ TEST_F(DocumentationTest, AnnotationBool) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "Bool", new BoolAnnotationVerifier("Bool") }} }; @@ -1517,7 +1475,6 @@ TEST_F(DocumentationTest, AnnotationInt) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "Int", new IntAnnotationVerifier("Int") }} }; @@ -1542,7 +1499,6 @@ TEST_F(DocumentationTest, AnnotationDouble) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "Double", new DoubleAnnotationVerifier("Double") }} }; @@ -1568,7 +1524,6 @@ TEST_F(DocumentationTest, AnnotationString) { using namespace std::string_literals; Documentation doc { - "Test", {{ "String", new StringAnnotationVerifier("String") }} }; @@ -1593,7 +1548,6 @@ TEST_F(DocumentationTest, AnnotationTable) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "Table", new TableAnnotationVerifier("Table") }} }; @@ -1618,7 +1572,6 @@ TEST_F(DocumentationTest, InRangeInt) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "Int", new InRangeVerifier(0, 5) }} }; @@ -1657,7 +1610,6 @@ TEST_F(DocumentationTest, InRangeDouble) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "Double", new InRangeVerifier(0.0, 5.0) }} }; @@ -1703,7 +1655,6 @@ TEST_F(DocumentationTest, NotInRangeInt) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "Int", new NotInRangeVerifier(0, 5) }} }; @@ -1753,7 +1704,6 @@ TEST_F(DocumentationTest, NotInRangeDouble) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "Double", new NotInRangeVerifier(0.0, 5.0) }} }; @@ -1803,7 +1753,6 @@ TEST_F(DocumentationTest, Wildcard) { using namespace openspace::documentation; Documentation doc { - "Test", {{ DocumentationEntry::Wildcard, new IntVerifier }} }; @@ -1860,7 +1809,6 @@ TEST_F(DocumentationTest, WildcardMixed) { using namespace openspace::documentation; Documentation doc { - "Test", { { DocumentationEntry::Wildcard, new IntVerifier }, { "b", new IntGreaterVerifier(5) } @@ -1935,7 +1883,6 @@ TEST_F(DocumentationTest, AndOperator) { using namespace openspace::documentation; Documentation doc { - "Test", { { "a", new AndVerifier( new IntGreaterEqualVerifier(2), new IntLessEqualVerifier(5) @@ -1975,7 +1922,6 @@ TEST_F(DocumentationTest, OrOperator) { using namespace std::string_literals; Documentation doc { - "Test", {{ "a", new OrVerifier(new StringVerifier, new IntVerifier)}} }; @@ -2007,7 +1953,6 @@ TEST_F(DocumentationTest, BoolVector2Verifier) { using namespace openspace::documentation; Documentation doc { - "Test", {{ "a", new BoolVector2Verifier }} }; @@ -2041,7 +1986,6 @@ TEST_F(DocumentationTest, IntVector2Verifier) { using namespace openspace::documentation; Documentation doc { - "Test", { { "a", new IntVector2Verifier } } }; @@ -2074,8 +2018,7 @@ TEST_F(DocumentationTest, IntVector2Verifier) { TEST_F(DocumentationTest, DoubleVector2Verifier) { using namespace openspace::documentation; - Documentation doc{ - "Test", + Documentation doc { { { "a", new DoubleVector2Verifier } } }; @@ -2109,7 +2052,6 @@ TEST_F(DocumentationTest, BoolVector3Verifier) { using namespace openspace::documentation; Documentation doc { - "Test", { { "a", new BoolVector3Verifier } } }; @@ -2143,7 +2085,6 @@ TEST_F(DocumentationTest, IntVector3Verifier) { using namespace openspace::documentation; Documentation doc { - "Test", { { "a", new IntVector3Verifier } } }; @@ -2177,7 +2118,6 @@ TEST_F(DocumentationTest, DoubleVector3Verifier) { using namespace openspace::documentation; Documentation doc { - "Test", { { "a", new DoubleVector3Verifier } } }; @@ -2211,7 +2151,6 @@ TEST_F(DocumentationTest, BoolVector4Verifier) { using namespace openspace::documentation; Documentation doc { - "Test", { { "a", new BoolVector4Verifier } } }; @@ -2245,7 +2184,6 @@ TEST_F(DocumentationTest, IntVector4Verifier) { using namespace openspace::documentation; Documentation doc { - "Test", { { "a", new IntVector4Verifier } } }; @@ -2279,7 +2217,6 @@ TEST_F(DocumentationTest, DoubleVector4Verifier) { using namespace openspace::documentation; Documentation doc { - "Test", { { "a", new DoubleVector4Verifier } } }; From 9b9f0ecce81312f96184846106158bdcfe735695 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Mon, 19 Sep 2016 10:32:14 +0200 Subject: [PATCH 86/92] Add a ReferencingVerifier to the list of available verifiers Require the Documentations identifier to be unique or empty --- .../openspace/documentation/documentation.h | 24 +++++-- .../documentation/documentationengine.h | 25 ++++++- include/openspace/documentation/verifier.h | 40 +++++++++++ include/openspace/documentation/verifier.inl | 4 +- src/documentation/documentationengine.cpp | 29 +++++--- src/documentation/verifier.cpp | 68 ++++++++++++++---- tests/test_documentation.inl | 69 ++++++++++++++++++- 7 files changed, 227 insertions(+), 32 deletions(-) diff --git a/include/openspace/documentation/documentation.h b/include/openspace/documentation/documentation.h index 25b770df8d..a200be79a8 100644 --- a/include/openspace/documentation/documentation.h +++ b/include/openspace/documentation/documentation.h @@ -57,10 +57,11 @@ struct TestResult { * The Reason for the offense */ enum class Reason { - MissingKey, ///< The offending key that was requested was not found - ExtraKey, ///< The exhaustive documentation contained an extra key - WrongType, ///< The key's value was not of the expected type - Verification ///< The value did not pass a necessary non-type verifier + MissingKey, ///< The offending key that was requested was not found + ExtraKey, ///< The exhaustive documentation contained an extra key + WrongType, ///< The key's value was not of the expected type + Verification, ///< The value did not pass a necessary non-type verifier + UnknownIdentifier ///< If the identifier for a ReferencingVerifier did not exist }; /// The offending key that caused the Offense. In the case of a nested table, /// this value will be the fully qualified name of the key @@ -216,9 +217,24 @@ struct Documentation { Documentation(std::string name, std::string id, DocumentationEntries entries = {}, Exhaustive exhaustive = Exhaustive::No); + /** + * Creates a Documentation with a human-readable \p name. + * \param name The human-readable name of this Documentation + * \param entries A list of DocumentationEntry%s that describe the individual keys for + * this entrie Documentation + * \param exhaustive Determines whether the \p entries are an exhaustive specification + * of the object or whether additional, potentially unused, keys are allowed + */ Documentation(std::string name, DocumentationEntries entries = {}, Exhaustive exhaustive = Exhaustive::No); + /** + * Creates a Documentation. + * \param entries A list of DocumentationEntry%s that describe the individual keys for + * this entrie Documentation + * \param exhaustive Determines whether the \p entries are an exhaustive specification + * of the object or whether additional, potentially unused, keys are allowed + */ Documentation(DocumentationEntries entries = {}, Exhaustive exhaustive = Exhaustive::No); /// The human-readable name of the Documentation diff --git a/include/openspace/documentation/documentationengine.h b/include/openspace/documentation/documentationengine.h index 99837e7bb4..7f8851686b 100644 --- a/include/openspace/documentation/documentationengine.h +++ b/include/openspace/documentation/documentationengine.h @@ -40,9 +40,20 @@ namespace documentation { */ class DocumentationEngine : public ghoul::Singleton { public: + /** + * This exception is thrown by the addDocumentation method if a provided Documentation + * has an identifier, but the identifier was registered previously. + */ struct DuplicateDocumentationException : public ghoul::RuntimeError { + /** + * Constructor of a DuplicateDocumentationException storing the offending + * Documentation for later use. + * \param documentation The Documentation whose identifier was previously + * registered + */ DuplicateDocumentationException(Documentation documentation); + /// The offending Documentation whose identifier was previously registered Documentation documentation; }; @@ -61,11 +72,21 @@ public: * Adds the \p documentation to the list of Documentation%s that are written to a * documentation file with the writeDocumentation method. * \param documentation The Documentation object that is to be stored for later use - * \throws DuplicateDocumentationException If the \p documentation did not have a - * unique identifier + * \throws DuplicateDocumentationException If the \p documentation has a non-empty + * identifier and it was not unique */ void addDocumentation(Documentation documentation); + /** + * Returns a list of all registered Documentation%s + * \return A list of all registered Documentation%s + */ + std::vector documentations() const; + + /** + * Returns a static reference to the main singleton DocumentationEngine + * \return A static reference to the main singleton DocumentationEngine + */ static DocumentationEngine& ref(); private: diff --git a/include/openspace/documentation/verifier.h b/include/openspace/documentation/verifier.h index d27a633453..15275a8539 100644 --- a/include/openspace/documentation/verifier.h +++ b/include/openspace/documentation/verifier.h @@ -580,6 +580,46 @@ struct AnnotationVerifier : public T { std::string annotation; }; +/** + * This Verifier can reference and apply other Documentation%s that have been registered + * with a DocumentationEngine. The dependency is only resolved when the operator() is + * called, at which the referencing Documentation must have been registered, or the + * TestResult will contain an offense of TestResult::Offense::Reason::UnknownIdentifier. + * If the referenced Documentation exists, the stored Table will be checked against that + * Documentation. + */ +struct ReferencingVerifier : public TableVerifier { + /** + * Creates a ReferencingVerifier that references a documentation with the provided + * \p identifier. The ReferencingVerifier will use the static DocumentationEngine to + * retrieve Documentation%s and find the \p identifier among them. + * \param identifier The identifier of the Documentation that this Verifier references + */ + ReferencingVerifier(std::string identifier); + + /** + * Checks whether the \p key in the \p dictionary exists and is of type Table (similar + * to the TableVerifier). If it exists and is a Table, the Documentation referenced by + * the identifier provided in the constructor is used to validate the Table. If the + * identifier does not name a registered Documentation, the TestResult::offenses + * will contain the \p key and TestResult::Offense::Reason::UnknownIdentifier will be + * signaled. If the identifier exists and the \p key%'s value does not comply with the + * Documentation, the offending keys will be returned in the TestResult with their + * fully qualified names. + * \param dictionary The ghoul::Dictionary whose \p key should be tested + * \param key The key contained in the \p dictionary that should be tested + * \return A TestResult struct that contains the results of the testing + */ + TestResult operator()(const ghoul::Dictionary& dictionary, + const std::string& key) const override; + + std::string documentation() const override; + + /// The identifier that references another Documentation registered with the + /// DocumentationEngine + std::string identifier; +}; + //---------------------------------------------------------------------------------------- // Misc verifiers //---------------------------------------------------------------------------------------- diff --git a/include/openspace/documentation/verifier.inl b/include/openspace/documentation/verifier.inl index f868c8432a..5c4fad2389 100644 --- a/include/openspace/documentation/verifier.inl +++ b/include/openspace/documentation/verifier.inl @@ -40,10 +40,10 @@ TestResult TemplateVerifier::operator()(const ghoul::Dictionary& dict, } else { if (dict.hasKey(key)) { - return { false, { { key, TestResult::Offense::Reason::MissingKey } } }; + return { false, { { key, TestResult::Offense::Reason::WrongType } } }; } else { - return { false, { { key, TestResult::Offense::Reason::WrongType } } }; + return { false, { { key, TestResult::Offense::Reason::MissingKey } } }; } } } diff --git a/src/documentation/documentationengine.cpp b/src/documentation/documentationengine.cpp index 7739d4ef64..e86b2a771f 100644 --- a/src/documentation/documentationengine.cpp +++ b/src/documentation/documentationengine.cpp @@ -236,18 +236,27 @@ void DocumentationEngine::writeDocumentation(const std::string& f, const std::st } void DocumentationEngine::addDocumentation(Documentation doc) { - auto it = std::find_if( - _documentations.begin(), - _documentations.end(), - [doc](const Documentation& d) { return doc.id == d.id; } - ); - - if (it != _documentations.end()) { - throw DuplicateDocumentationException(std::move(doc)); - } - else { + if (doc.id.empty()) { _documentations.push_back(std::move(doc)); } + else { + auto it = std::find_if( + _documentations.begin(), + _documentations.end(), + [doc](const Documentation& d) { return doc.id == d.id; } + ); + + if (it != _documentations.end()) { + throw DuplicateDocumentationException(std::move(doc)); + } + else { + _documentations.push_back(std::move(doc)); + } + } +} + +std::vector DocumentationEngine::documentations() const { + return _documentations; } } // namespace documentation diff --git a/src/documentation/verifier.cpp b/src/documentation/verifier.cpp index 9af9f7b22a..7e90e34be3 100644 --- a/src/documentation/verifier.cpp +++ b/src/documentation/verifier.cpp @@ -24,6 +24,8 @@ #include +#include + namespace openspace { namespace documentation { @@ -85,11 +87,10 @@ std::string DoubleVerifier::type() const { } TestResult IntVerifier::operator()(const ghoul::Dictionary & dict, - const std::string & key) const -{ + const std::string & key) const { if (dict.hasKeyAndValue(key)) { // We we have a key and the value is int, we are done - return { true, {} }; + return{ true, {} }; } else { if (dict.hasKey(key)) { @@ -99,19 +100,19 @@ TestResult IntVerifier::operator()(const ghoul::Dictionary & dict, double intPart; bool isInt = modf(value, &intPart) == 0.0; if (isInt) { - return { true,{} }; + return{ true,{} }; } else { - return { false, { { key, TestResult::Offense::Reason::WrongType } } }; + return{ false, { { key, TestResult::Offense::Reason::WrongType } } }; } } else { // If we don't have a double value, we cannot have an int value - return { false, { { key, TestResult::Offense::Reason::WrongType } } }; + return{ false, { { key, TestResult::Offense::Reason::WrongType } } }; } } else { - return { false, { {key, TestResult::Offense::Reason::MissingKey }}}; + return{ false, { {key, TestResult::Offense::Reason::MissingKey }} }; } } } @@ -126,12 +127,10 @@ std::string StringVerifier::type() const { TableVerifier::TableVerifier(std::vector d, Exhaustive exhaustive) : documentations(std::move(d)) - , exhaustive(std::move(exhaustive)) -{} + , exhaustive(std::move(exhaustive)) {} TestResult TableVerifier::operator()(const ghoul::Dictionary& dict, - const std::string& key) const -{ + const std::string& key) const { if (dict.hasKeyAndValue(key)) { ghoul::Dictionary d = dict.value(key); TestResult res = testSpecification({ "", documentations, exhaustive }, d); @@ -144,11 +143,11 @@ TestResult TableVerifier::operator()(const ghoul::Dictionary& dict, } else { if (dict.hasKey(key)) { - return { false, { { key, TestResult::Offense::Reason::WrongType } } }; + return{ false, { { key, TestResult::Offense::Reason::WrongType } } }; } else { - return { false, { { key, TestResult::Offense::Reason::MissingKey } } }; + return{ false, { { key, TestResult::Offense::Reason::MissingKey } } }; } } } @@ -157,6 +156,49 @@ std::string TableVerifier::type() const { return "Table"; } +ReferencingVerifier::ReferencingVerifier(std::string id) + : identifier(std::move(id)) +{ + ghoul_assert(!identifier.empty(), "identifier must not be empty"); +} + +TestResult ReferencingVerifier::operator()(const ghoul::Dictionary& dictionary, + const std::string& key) const +{ + TestResult res = TableVerifier::operator()(dictionary, key); + if (res.success) { + std::vector documentations = DocEng.documentations(); + + auto it = std::find_if( + documentations.begin(), + documentations.end(), + [this](const Documentation& doc) { return doc.id == identifier; } + ); + + if (it == documentations.end()) { + return { false, { { key, TestResult::Offense::Reason::UnknownIdentifier } } }; + } + else { + ghoul::Dictionary d = dictionary.value(key); + TestResult res = testSpecification(*it, d); + + for (TestResult::Offense& s : res.offenses) { + s.offender = key + "." + s.offender; + } + + return res; + } + } + else { + return res; + } +} + +std::string ReferencingVerifier::documentation() const { + using namespace std::string_literals; + return "Referencing Documentation: '"s + identifier + "'"; +} + AndVerifier::AndVerifier(Verifier* lhs, Verifier* rhs) : lhs(lhs) , rhs(rhs) diff --git a/tests/test_documentation.inl b/tests/test_documentation.inl index 3c78dd3ca3..35b6bca709 100644 --- a/tests/test_documentation.inl +++ b/tests/test_documentation.inl @@ -25,6 +25,7 @@ #include "gtest/gtest.h" #include +#include #include #include @@ -173,7 +174,7 @@ TEST_F(DocumentationTest, BoolVerifier) { EXPECT_EQ(0, positiveRes.offenses.size()); ghoul::Dictionary negative { - { "Bool", 0} + { "Bool", 0 } }; TestResult negativeRes = testSpecification(doc, negative); EXPECT_FALSE(negativeRes.success); @@ -1879,6 +1880,67 @@ TEST_F(DocumentationTest, WildcardMixed) { EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[1].reason); } +TEST_F(DocumentationTest, Referencing) { + using namespace openspace::documentation; + + Documentation referenced { + "Referenced Name", + "referenced_id", + { + { "a", new IntVerifier }, + { "b", new DoubleVerifier } + }, + }; + DocEng.addDocumentation(referenced); + + Documentation doc {{ + { "Table", new ReferencingVerifier("referenced_id") } + }}; + + ghoul::Dictionary positive { + { "Table", ghoul::Dictionary{ { "a", 1 }, { "b", 2.0 } }} + }; + + TestResult positiveRes = testSpecification(doc, positive); + EXPECT_TRUE(positiveRes.success); + EXPECT_EQ(0, positiveRes.offenses.size()); + + ghoul::Dictionary negative { + { "Table", 1 } + }; + TestResult negativeRes = testSpecification(doc, negative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Table", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); + + ghoul::Dictionary negative2 { + { "Table", ghoul::Dictionary{ { "a", 1 }, { "b", true }}} + }; + negativeRes = testSpecification(doc, negative2); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Table.b", negativeRes.offenses[0].offender); + EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason); + + + Documentation wrongDoc {{ + { "Table", new ReferencingVerifier("WRONG") } + } }; + ghoul::Dictionary wrongNegative { + { "Table", ghoul::Dictionary{ { "a", 1 },{ "b", 2.0 } } } + }; + negativeRes = testSpecification(wrongDoc, wrongNegative); + EXPECT_FALSE(negativeRes.success); + ASSERT_EQ(1, negativeRes.offenses.size()); + EXPECT_EQ("Table", negativeRes.offenses[0].offender); + EXPECT_EQ( + TestResult::Offense::Reason::UnknownIdentifier, + negativeRes.offenses[0].reason + ); +} + + TEST_F(DocumentationTest, AndOperator) { using namespace openspace::documentation; @@ -2303,6 +2365,8 @@ TEST_F(DocumentationTest, VerifierTypePostConditions) { EXPECT_NE("", DoubleAnnotationVerifier("Annotation"s).type()); EXPECT_NE("", StringAnnotationVerifier("Annotation"s).type()); EXPECT_NE("", TableAnnotationVerifier("Annotation"s).type()); + + EXPECT_NE("", ReferencingVerifier("identifier"s).type()); } TEST_F(DocumentationTest, VerifierDocumentationPostConditions) { @@ -2362,4 +2426,7 @@ TEST_F(DocumentationTest, VerifierDocumentationPostConditions) { EXPECT_NE("", DoubleAnnotationVerifier("Annotation"s).documentation()); EXPECT_NE("", StringAnnotationVerifier("Annotation"s).documentation()); EXPECT_NE("", TableAnnotationVerifier("Annotation"s).documentation()); + + EXPECT_NE("", ReferencingVerifier("identifier"s).documentation()); + } From 85492405bdbe52fc77d1acee6741d4928d4b5471 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Mon, 19 Sep 2016 11:24:37 +0200 Subject: [PATCH 87/92] Make use of referenced verifier for Renderables Adapt HTML documentation generation --- include/openspace/rendering/renderable.h | 4 +++ src/documentation/documentationengine.cpp | 24 ++++++++++++++-- src/engine/openspaceengine.cpp | 2 ++ src/rendering/renderable.cpp | 35 +++++++++++++++++------ src/scene/scenegraphnode_doc.inl | 12 +------- 5 files changed, 54 insertions(+), 23 deletions(-) diff --git a/include/openspace/rendering/renderable.h b/include/openspace/rendering/renderable.h index 36cbf1d20b..77904bd646 100644 --- a/include/openspace/rendering/renderable.h +++ b/include/openspace/rendering/renderable.h @@ -32,6 +32,8 @@ #include +#include + // Forward declare to minimize dependencies namespace ghoul { @@ -91,6 +93,8 @@ public: static void setPscUniforms(ghoul::opengl::ProgramObject& program, const Camera& camera, const PowerScaledCoordinate& position); + static Documentation Documentation(); + protected: properties::BoolProperty _enabled; diff --git a/src/documentation/documentationengine.cpp b/src/documentation/documentationengine.cpp index e86b2a771f..d1a0e41ca6 100644 --- a/src/documentation/documentationengine.cpp +++ b/src/documentation/documentationengine.cpp @@ -125,16 +125,34 @@ std::string generateHtmlDocumentation(const Documentation& d) { std::stringstream html; html << "\t\n" - << "\t\t" << d.name << "\n"; + << "\t\t" << d.name << "\n"; for (const auto& p : d.entries) { html << "\t\n" << "\t\t\n" << "\t\t" << p.key << "\n" - << "\t\t" << (p.optional ? "true" : "false") << "\n" + << "\t\t" << (p.optional ? "Optional" : "Required") << "\n" << "\t\t" << p.verifier->type() << "\n"; + TableVerifier* tv = dynamic_cast(p.verifier.get()); - if (tv) { + ReferencingVerifier* rv = dynamic_cast(p.verifier.get()); + + // We have to check ReferencingVerifier first as a ReferencingVerifier is also a + // TableVerifier + if (rv) { + std::vector documentations = DocEng.documentations(); + auto it = std::find_if( + documentations.begin(), + documentations.end(), + [rv](const Documentation& doc) { return doc.id == rv->identifier; } + ); + + html << "\t\t" + << "\t\t\tReferencing: " + << "identifier << "\">" << it->name << "" + << "\t\t"; + } + else if (tv) { // We have a TableVerifier, so we need to recurse html << "\n" << "\t\n" diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 8186ee8cc8..aeebc22124 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -165,6 +165,8 @@ OpenSpaceEngine::OpenSpaceEngine(std::string programName, DocEng.addDocumentation(ConfigurationManager::Documentation()); DocEng.addDocumentation(Scene::Documentation()); + DocEng.addDocumentation(SceneGraphNode::Documentation()); + DocEng.addDocumentation(Renderable::Documentation()); } OpenSpaceEngine::~OpenSpaceEngine() { diff --git a/src/rendering/renderable.cpp b/src/rendering/renderable.cpp index 14db2e226b..3313c432ef 100644 --- a/src/rendering/renderable.cpp +++ b/src/rendering/renderable.cpp @@ -28,6 +28,8 @@ #include #include +#include + #include #include #include @@ -42,22 +44,37 @@ namespace { namespace openspace { +Documentation Renderable::Documentation() { + using namespace openspace::documentation; + + return { + "Renderable", + "renderable", + { + { + KeyType, + new StringAnnotationVerifier("A valid Renderable created by a factory"), + "This key specifies the type of Renderable that gets created. It has to be one" + "of the valid Renderables that are available for creation (see the " + "FactoryDocumentation for a list of possible Renderables), which depends on " + "the configration of the application", + Optional::No + } + } + }; +} + Renderable* Renderable::createFromDictionary(const ghoul::Dictionary& dictionary) { // The name is passed down from the SceneGraphNode std::string name; bool success = dictionary.getValue(SceneGraphNode::KeyName, name); - assert(success); + ghoul_assert(success, "The SceneGraphNode did not set the 'name' key"); - std::string renderableType; - success = dictionary.getValue(KeyType, renderableType); + documentation::testSpecificationAndThrow(Documentation(), dictionary, "Renderable"); - if (!success) { - LERROR("Renderable '" << name << "' did not have key '" << KeyType << "'"); - return nullptr; - } + std::string renderableType = dictionary.value(KeyType); - ghoul::TemplateFactory* factory - = FactoryManager::ref().factory(); + auto factory = FactoryManager::ref().factory(); Renderable* result = factory->create(renderableType, dictionary); if (result == nullptr) { LERROR("Failed to create a Renderable object of type '" << renderableType << "'"); diff --git a/src/scene/scenegraphnode_doc.inl b/src/scene/scenegraphnode_doc.inl index b10c8e6468..a7fc152599 100644 --- a/src/scene/scenegraphnode_doc.inl +++ b/src/scene/scenegraphnode_doc.inl @@ -52,17 +52,7 @@ Documentation SceneGraphNode::Documentation() { }, { "Renderable", - new TableVerifier({ - { - "Type", - new StringAnnotationVerifier( - "Must name a valid Renderable type." - ), - "The type of the specific renderable. The list of available " - "renderables depends on the configuration of the application and can " - "be written to disk at startup." - } - }), + new ReferencingVerifier("renderable"), "The renderable that is to be created for this scenegraph node. A renderable " "is a component of a scenegraph node that will lead to some visual result on " "the screen. The specifics heavily depend on the 'Type' of the renderable. " From d8f61e736ab0ca5414c02c8fb4a227e147d4dfb9 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Mon, 19 Sep 2016 14:02:04 +0200 Subject: [PATCH 88/92] Clean up gitignore file --- .gitignore | 167 +++++++++++++++++++++++------------------------------ ext/ghoul | 2 +- 2 files changed, 74 insertions(+), 95 deletions(-) diff --git a/.gitignore b/.gitignore index 82afb83024..0980cb3856 100644 --- a/.gitignore +++ b/.gitignore @@ -1,21 +1,21 @@ -bin/ -build/ -cache/ -tmp/ -ext/SGCT -.DS_Store -*.swp -.vscode - -# Windows system files: -Thumbs.db - -# Emacs backup files: *~ +*.swp +.DS_Store +.vscode +/bin/ +/build/ +/cache/ +Thumbs.db +tmp/ + +/documentation +/doc +/ext/SGCT -# generated glsl files *.gglsl *.GhoulGenerated.glsl +*.OpenSpaceGenerated.glsl + shaders/generated/* # CMake stuff @@ -29,88 +29,67 @@ install_manifest.txt .cproject .project -# Doxygen stuff shaders/ABuffer/constants.hglsl -*.OpenSpaceGenerated.glsl log.html -data/scene/rosetta/67P/obj/67P_rotated_5_130.obj -data/spice/NewHorizonsKernels/ -data/scene/newhorizons/pluto/pluto/textures/ -data/scene/newhorizons/pluto/pluto/utcEvents.txt -data/scene/rosetta/rosetta/textures/* -data/scene/saturn/textures/saturn.jpg -data/scene/stars/colorbv.cmap -data/scene/stars/speck/stars.speck -data/scene/stars/textures/glare.png -data/scene/stars/textures/halo.png -data/scene/sun/textures/ -data/scene/uranus/textures/uranus.jpg -data/scene/venus/textures/venus.jpg -data/scene/dawn/vestaprojection/VestaComet/VestaComet_5000.obj -data/spice/DawnKernels/ -data/scene/newhorizons/jupiter/jupiter/ProjectionsOfInterest/ -data/scene/rosetta/67P/textures -data/scene/newhorizons/jupiter/callisto/textures/callisto.jpg -data/scene/dawn/ceres/textures/gray.png -data/scene/newhorizons/pluto/charon/textures/ -data/scene/dawn/dawn/obj/ -data/scene/dawn/dawn/textures/ -data/scene/earth/textures/ -data/scene/moon/textures/Moon16k.dds -data/scene/newhorizons/jupiter/europa/textures/europa.jpg -data/scene/newhorizons/jupiter/ganymede/textures/ganymede.jpg -data/scene/newhorizons/jupiter/io/textures/io.jpg -data/scene/jupiter/jupiter/textures/jupiter.jpg -data/scene/mars/textures/mars.jpg -data/scene/mercury/textures/mercury.jpg -data/scene/milkyway/textures/DarkUniverse_mellinger_8k.jpg -data/scene/neptune/textures/neptune.jpg -data/scene/newhorizons/newhorizons/models/ -data/scene/newhorizons/newhorizons/textures/ -data/scene/pluto/textures/ -data/scene/pluto/textures/Shenk_180.jpg -data/scene/pluto/textures/pluto_highres_180.jpg -data/scene/newhorizons/pluto/pluto/assets/core_v9h_obs_getmets_v8_time_fix_nofrcd_mld.txt -data/scene/newhorizons/pluto/pluto/textures/3.jpg -data/scene/newhorizons/pluto/pluto/textures/Pluto-Text.png -data/scene/dawn/vestaprojection/VestaComet/VestaComet.mtl -data/scene/dawn/vestaprojection/textures/ -data/spice/MAR063.BSP -data/spice/de430_1850-2150.bsp -data/spice/jup260.bsp -data/BATSRUS.cdf -data/ENLIL.cdf -data/scene/newhorizons/pluto/pluto/images -data/spice/nh_kernels/ -data/scene/jupiter/jupiter/textures/Jupiter-text.png -data/scene/jupiter/callisto/textures/callisto.jpg -data/scene/jupiter/europa/textures/europa.jpg -data/scene/jupiter/ganymede/textures/ganymede.jpg -data/scene/jupiter/io/textures/io.jpg -data/scene/milkyway-eso/textures/eso0932a_blend.png -data/scene/stars-denver/denver_colorbv.cmap -data/scene/stars-denver/speck/stars.speck -data/scene/stars-denver/textures/halo.png -data/scene/newhorizons/pluto/pluto/full_images/ -data/scene/rosetta/67P/rosettaimages/ -data/scene/newhorizons/pluto/charon/utcEvents.txt -data/scene/rosetta/67P/obj/67P_HD_2015-05-09.obj -data/scene/rosetta/67P/obj/may9_map.jpg -data/scene/rosetta/67P/textures/may9_map.jpg -data/scene/newhorizons/pluto/charon/textures/cpdem-Mcolor2-MLorriCA-lr-5_ZMfs-cyl.jpg -data/scene/newhorizons/pluto/charon/textures/cpmap_cyl_HR_0e.jpg -data/scene/volumetricmilkyway/milkyway/ ScriptLog.txt -data/scene/atmosphereearth/textures/ -data/scene/juno/juno/textures -data/scene/juno/juno/spice + +data/scene/atmosphereearth/textures +data/scene/dawn/ceres/textures +data/scene/dawn/dawn/obj +data/scene/dawn/dawn/textures +data/scene/dawn/vestaprojection/textures +data/scene/dawn/vestaprojection/VestaComet +data/scene/debugglobe/textures +data/scene/earth/textures data/scene/juno/juno/Juno.mtl data/scene/juno/juno/Juno.obj -saturn_rings.png -data/scene/debugglobe/textures/ -data/scene/rosetta/rosetta/obj/Rosetta.obj -data/scene/rosetta/rosetta/rosetta/ -data/scene/rosetta/rosetta/textures/ -data/spice/Rosetta/ -documentation/ -doc/ +data/scene/juno/juno/spice +data/scene/juno/juno/textures +data/scene/jupiter/callisto/textures +data/scene/jupiter/europa/textures +data/scene/jupiter/ganymede/textures +data/scene/jupiter/io/textures +data/scene/jupiter/jupiter/textures +data/scene/mars/textures +data/scene/mercury/textures +data/scene/milkyway/textures +data/scene/milkyway-eso/textures +data/scene/moon/textures +data/scene/neptune/textures +data/scene/newhorizons/jupiter/callisto/textures +data/scene/newhorizons/jupiter/europa/textures +data/scene/newhorizons/jupiter/ganymede/textures +data/scene/newhorizons/jupiter/io/textures +data/scene/newhorizons/jupiter/jupiter/ProjectionsOfInterest +data/scene/newhorizons/newhorizons/models +data/scene/newhorizons/newhorizons/textures +data/scene/newhorizons/pluto/charon/textures +data/scene/newhorizons/pluto/pluto/assets +data/scene/newhorizons/pluto/pluto/full_images +data/scene/newhorizons/pluto/pluto/images +data/scene/newhorizons/pluto/pluto/textures +data/scene/pluto/textures +data/scene/saturn/textures +data/scene/rosetta/67P/obj +data/scene/rosetta/67P/rosettaimages +data/scene/rosetta/67P/textures +data/scene/rosetta/rosetta/rosetta +data/scene/rosetta/rosetta/textures +data/scene/stars/colorbv.cmap +data/scene/stars/speck +data/scene/stars/textures +data/scene/stars-denver/denver_colorbv.cmap +data/scene/stars-denver/speck +data/scene/stars-denver/textures +data/scene/sun/textures +data/scene/uranus/textures +data/scene/venus/textures +data/scene/volumetricmilkyway/milkyway +data/spice/DawnKernels +data/spice/jup260.bsp +data/spice/de430_1850-2150.bsp +data/spice/MAR063.BSP +data/spice/NewHorizonsKernels +data/spice/nh_kernels +data/spice/Rosetta + diff --git a/ext/ghoul b/ext/ghoul index e10dc7cc5f..db86a30fd0 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit e10dc7cc5fbfd5c4d74b525f55ade7bc339e5bc6 +Subproject commit db86a30fd0f0aa1be9f3723a53acd7e85319e2a9 From 8867b3439fa64e62649a1705ed67a96a6c63af8c Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Mon, 19 Sep 2016 14:03:42 +0200 Subject: [PATCH 89/92] Add central location for the core to register documentations Add documentation to ScreenSpaceRenderable Add documentation to Ephemeris Add documentation to Rotation --- .../documentation/core_registration.h | 38 +++++++++++++ .../rendering/screenspacerenderable.h | 4 ++ include/openspace/scene/ephemeris.h | 4 ++ include/openspace/scene/rotation.h | 4 ++ include/openspace/scene/scale.h | 4 ++ modules/base/scale/staticscale.h | 2 +- src/CMakeLists.txt | 2 + src/documentation/core_registration.cpp | 53 +++++++++++++++++++ src/engine/openspaceengine.cpp | 7 +-- src/rendering/screenspacerenderable.cpp | 34 +++++++++--- src/scene/ephemeris.cpp | 22 ++++++++ src/scene/rotation.cpp | 35 ++++++++---- src/scene/scale.cpp | 37 +++++++++---- src/scene/scenegraphnode_doc.inl | 39 ++------------ 14 files changed, 219 insertions(+), 66 deletions(-) create mode 100644 include/openspace/documentation/core_registration.h create mode 100644 src/documentation/core_registration.cpp diff --git a/include/openspace/documentation/core_registration.h b/include/openspace/documentation/core_registration.h new file mode 100644 index 0000000000..d29259daf2 --- /dev/null +++ b/include/openspace/documentation/core_registration.h @@ -0,0 +1,38 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __CORE_REGISTRATION_H__ +#define __CORE_REGISTRATION_H__ + +namespace openspace { +namespace documentation { + +class DocumentationEngine; + +void registerCoreClasses(documentation::DocumentationEngine& engine); + +} // namespace documentation +} // namespace openspace + +#endif // __CORE_REGISTRATION_H__ diff --git a/include/openspace/rendering/screenspacerenderable.h b/include/openspace/rendering/screenspacerenderable.h index 9fa4c175c8..46cea14e32 100644 --- a/include/openspace/rendering/screenspacerenderable.h +++ b/include/openspace/rendering/screenspacerenderable.h @@ -35,6 +35,8 @@ #include #include +#include + namespace openspace { /** @@ -63,6 +65,8 @@ public: glm::vec3 sphericalPosition() const; float depth() const; + static openspace::Documentation Documentation(); + protected: void createPlane(); void useEuclideanCoordinates(bool b); diff --git a/include/openspace/scene/ephemeris.h b/include/openspace/scene/ephemeris.h index 026e024b24..ff7ae0a441 100644 --- a/include/openspace/scene/ephemeris.h +++ b/include/openspace/scene/ephemeris.h @@ -29,6 +29,8 @@ #include #include +#include + namespace openspace { class Ephemeris { @@ -41,6 +43,8 @@ public: virtual const glm::dvec3& position() const = 0; virtual void update(const UpdateData& data); + static openspace::Documentation Documentation(); + protected: Ephemeris(); }; diff --git a/include/openspace/scene/rotation.h b/include/openspace/scene/rotation.h index f5f3620382..42e35bd3bd 100644 --- a/include/openspace/scene/rotation.h +++ b/include/openspace/scene/rotation.h @@ -28,6 +28,8 @@ #include #include +#include + namespace openspace { class Rotation { @@ -40,6 +42,8 @@ public: virtual const glm::dmat3& matrix() const = 0; virtual void update(const UpdateData& data); + static openspace::Documentation Documentation(); + protected: Rotation(); }; diff --git a/include/openspace/scene/scale.h b/include/openspace/scene/scale.h index d7f0ce9703..0e34d3f631 100644 --- a/include/openspace/scene/scale.h +++ b/include/openspace/scene/scale.h @@ -28,6 +28,8 @@ #include #include +#include + namespace openspace { class Scale { @@ -40,6 +42,8 @@ public: virtual double scaleValue() const = 0; virtual void update(const UpdateData& data); + static openspace::Documentation Documentation(); + protected: Scale(); }; diff --git a/modules/base/scale/staticscale.h b/modules/base/scale/staticscale.h index 5725f06a06..c2e64948b0 100644 --- a/modules/base/scale/staticscale.h +++ b/modules/base/scale/staticscale.h @@ -37,7 +37,7 @@ public: StaticScale(const ghoul::Dictionary& dictionary); double scaleValue() const; - static Documentation Documentation(); + static openspace::Documentation Documentation(); private: double _scaleValue; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6c87e7cd57..7b4e1c6ea2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -24,6 +24,7 @@ set(OPENSPACE_SOURCE ${OPENSPACE_BASE_DIR}/src/openspace.cpp + ${OPENSPACE_BASE_DIR}/src/documentation/core_registration.cpp ${OPENSPACE_BASE_DIR}/src/documentation/documentation.cpp ${OPENSPACE_BASE_DIR}/src/documentation/documentationengine.cpp ${OPENSPACE_BASE_DIR}/src/documentation/verifier.cpp @@ -111,6 +112,7 @@ set(OPENSPACE_SOURCE set(OPENSPACE_HEADER ${OPENSPACE_BASE_DIR}/include/openspace/openspace.h + ${OPENSPACE_BASE_DIR}/include/openspace/documentation/core_registration.h ${OPENSPACE_BASE_DIR}/include/openspace/documentation/documentation.h ${OPENSPACE_BASE_DIR}/include/openspace/documentation/documentationengine.h ${OPENSPACE_BASE_DIR}/include/openspace/documentation/verifier.h diff --git a/src/documentation/core_registration.cpp b/src/documentation/core_registration.cpp new file mode 100644 index 0000000000..9f938c477e --- /dev/null +++ b/src/documentation/core_registration.cpp @@ -0,0 +1,53 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace openspace { +namespace documentation { + +void registerCoreClasses(documentation::DocumentationEngine& engine) { + engine.addDocumentation(ConfigurationManager::Documentation()); + engine.addDocumentation(Ephemeris::Documentation()); + engine.addDocumentation(Renderable::Documentation()); + engine.addDocumentation(Rotation::Documentation()); + engine.addDocumentation(Scale::Documentation()); + engine.addDocumentation(Scene::Documentation()); + engine.addDocumentation(SceneGraphNode::Documentation()); + engine.addDocumentation(ScreenSpaceRenderable::Documentation()); +} + +} // namespace documentation +} // namespace openspace diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index aeebc22124..cc10e32912 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -26,6 +26,7 @@ #include +#include #include #include #include @@ -162,11 +163,6 @@ OpenSpaceEngine::OpenSpaceEngine(std::string programName, Time::initialize(); ghoul::systemcapabilities::SystemCapabilities::initialize(); TransformationManager::initialize(); - - DocEng.addDocumentation(ConfigurationManager::Documentation()); - DocEng.addDocumentation(Scene::Documentation()); - DocEng.addDocumentation(SceneGraphNode::Documentation()); - DocEng.addDocumentation(Renderable::Documentation()); } OpenSpaceEngine::~OpenSpaceEngine() { @@ -301,6 +297,7 @@ bool OpenSpaceEngine::create(int argc, char** argv, // Register modules _engine->_moduleEngine->initialize(); + documentation::registerCoreClasses(DocEng); // After registering the modules, the documentations for the available classes // can be added as well for (OpenSpaceModule* m : _engine->_moduleEngine->modules()) { diff --git a/src/rendering/screenspacerenderable.cpp b/src/rendering/screenspacerenderable.cpp index dc047dd558..c95734a2b9 100644 --- a/src/rendering/screenspacerenderable.cpp +++ b/src/rendering/screenspacerenderable.cpp @@ -30,6 +30,8 @@ #include #include +#include + #ifdef WIN32 #define _USE_MATH_DEFINES #include @@ -50,16 +52,36 @@ namespace { namespace openspace { +Documentation ScreenSpaceRenderable::Documentation() { + using namespace openspace::documentation; + + return { + "Screenspace Renderable", + "core_screenspacerenderable", + { + { + KeyType, + new StringAnnotationVerifier("Must name a valid Screenspace renderable"), + "The type of the Screenspace renderable that is to be created. The " + "available types of Screenspace renderable depend on the configuration of" + "the application and can be written to disk on application startup into " + "the FactoryDocumentation.", + Optional::No + } + } + }; +} + ScreenSpaceRenderable* ScreenSpaceRenderable::createFromDictionary( const ghoul::Dictionary& dictionary) { - std::string renderableType; - bool success = dictionary.getValue(KeyType, renderableType); + documentation::testSpecificationAndThrow( + Documentation(), + dictionary, + "ScreenSpaceRenderable" + ); - if (!success) { - LERROR("ScreenSpaceRenderable did not have key '" << KeyType << "'"); - return nullptr; - } + std::string renderableType = dictionary.value(KeyType); auto factory = FactoryManager::ref().factory(); ScreenSpaceRenderable* result = factory->create(renderableType, dictionary); diff --git a/src/scene/ephemeris.cpp b/src/scene/ephemeris.cpp index f7088b3234..7bba161310 100644 --- a/src/scene/ephemeris.cpp +++ b/src/scene/ephemeris.cpp @@ -26,6 +26,8 @@ #include #include +#include + namespace { const std::string _loggerCat = "Ephemeris"; const std::string KeyType = "Type"; @@ -33,6 +35,26 @@ namespace { namespace openspace { +Documentation Ephemeris::Documentation() { + using namespace openspace::documentation; + + return{ + "Transformation Translation", + "core_transform_translation", + { + { + KeyType, + new StringAnnotationVerifier("Must name a valid Translation type"), + "The type of translation that is described in this element. " + "The available types of translations depend on the " + "configuration of the application and can be written to disk " + "on application startup into the FactoryDocumentation.", + Optional::No + } + } + }; +} + Ephemeris* Ephemeris::createFromDictionary(const ghoul::Dictionary& dictionary) { if (!dictionary.hasValue(KeyType)) { LERROR("Ephemeris did not have key '" << KeyType << "'"); diff --git a/src/scene/rotation.cpp b/src/scene/rotation.cpp index 74a026fe3f..a4d77d54ff 100644 --- a/src/scene/rotation.cpp +++ b/src/scene/rotation.cpp @@ -26,6 +26,8 @@ #include #include +#include + namespace { const std::string _loggerCat = "Rotation"; const std::string KeyType = "Type"; @@ -33,16 +35,31 @@ namespace { namespace openspace { -Rotation* Rotation::createFromDictionary(const ghoul::Dictionary& dictionary) { - if (!dictionary.hasValue(KeyType)) { - LERROR("Ephemeris did not have key '" << KeyType << "'"); - return nullptr; - } +Documentation Rotation::Documentation() { + using namespace openspace::documentation; - std::string rotationType; - dictionary.getValue(KeyType, rotationType); - ghoul::TemplateFactory* factory - = FactoryManager::ref().factory(); + return { + "Transformation Rotation", + "core_transform_rotation", + { + { + KeyType, + new StringAnnotationVerifier("Must name a valid Rotation type."), + "The type of the rotation that is described in this element. The " + "available types of rotations depend on the configuration of the " + "application and can be written to disk on application startup into the " + "FactoryDocumentation.", + Optional::No + } + } + }; +} + +Rotation* Rotation::createFromDictionary(const ghoul::Dictionary& dictionary) { + documentation::testSpecificationAndThrow(Documentation(), dictionary, "Rotation"); + + std::string rotationType = dictionary.value(KeyType); + auto factory = FactoryManager::ref().factory(); Rotation* result = factory->create(rotationType, dictionary); if (result == nullptr) { LERROR("Failed creating Rotation object of type '" << rotationType << "'"); diff --git a/src/scene/scale.cpp b/src/scene/scale.cpp index 09812c9b3e..22bd2d7cbe 100644 --- a/src/scene/scale.cpp +++ b/src/scene/scale.cpp @@ -26,6 +26,8 @@ #include #include +#include + namespace { const std::string _loggerCat = "Scale"; const std::string KeyType = "Type"; @@ -33,16 +35,33 @@ namespace { namespace openspace { -Scale* Scale::createFromDictionary(const ghoul::Dictionary& dictionary) { - if (!dictionary.hasValue(KeyType)) { - LERROR("Ephemeris did not have key '" << KeyType << "'"); - return nullptr; - } +Documentation Scale::Documentation() { + using namespace openspace::documentation; - std::string scaleType; - dictionary.getValue(KeyType, scaleType); - ghoul::TemplateFactory* factory - = FactoryManager::ref().factory(); + return { + "Transformation Scaling", + "core_transform_scaling", + { + { + KeyType, + new StringAnnotationVerifier("Must name a valid Scale type"), + "The type of the scaling that is described in this element. " + "The available types of scaling depend on the configuration " + "of the application and can be written to disk on " + "application startup into the FactoryDocumentation.", + Optional::No + } + } + }; +} + + +Scale* Scale::createFromDictionary(const ghoul::Dictionary& dictionary) { + documentation::testSpecificationAndThrow(Documentation(), dictionary, "Scale"); + + std::string scaleType = dictionary.value(KeyType); + + auto factory = FactoryManager::ref().factory(); Scale* result = factory->create(scaleType, dictionary); if (result == nullptr) { LERROR("Failed creating Scale object of type '" << scaleType << "'"); diff --git a/src/scene/scenegraphnode_doc.inl b/src/scene/scenegraphnode_doc.inl index a7fc152599..5a491fb139 100644 --- a/src/scene/scenegraphnode_doc.inl +++ b/src/scene/scenegraphnode_doc.inl @@ -66,18 +66,7 @@ Documentation SceneGraphNode::Documentation() { new TableVerifier({ { "Translation", - new TableVerifier({ - { - "Type", - new StringAnnotationVerifier( - "Must name a valid Translation type." - ), - "The type of translation that is described in this element. " - "The available types of translations depend on the " - "configuration of the application and can be written to disk " - "on application startup." - } - }), + new ReferencingVerifier("core_transform_translation"), "This node describes a translation that is applied to the scenegraph " "node and all its children. Depending on the 'Type' of the " "translation, this can either be a static translation or a " @@ -86,18 +75,7 @@ Documentation SceneGraphNode::Documentation() { }, { "Rotation", - new TableVerifier({ - { - "Type", - new StringAnnotationVerifier( - "Must name a valid Rotation type." - ), - "The type of the rotation that is described in this element. " - "The available types of rotations depend on the " - "configuration of the application and can be written to disk " - "on application startup." - } - }), + new ReferencingVerifier("core_transform_rotation"), "This nodes describes a rotation that is applied to the scenegraph " "node and all its children. Depending on the 'Type' of the rotation, " "this can either be a static rotation or a time-varying one.", @@ -105,18 +83,7 @@ Documentation SceneGraphNode::Documentation() { }, { "Scale", - new TableVerifier({ - { - "Type", - new StringAnnotationVerifier( - "Must name a valid Scale type." - ), - "The type of the scaling that is described in this element. " - "The available types of scaling depend on the configuration " - "of the application and can be written to disk on " - "application startup." - } - }), + new ReferencingVerifier("core_transform_scaling"), "This node describes a scaling that is applied to the scenegraph " "node and all its children. Depending on the 'Type' of the scaling, " "this can either be a static scaling or a time-varying one.", From 6637ae284969cde70c9710b27b47532922bdb919 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Mon, 19 Sep 2016 22:45:45 +0200 Subject: [PATCH 90/92] Update Ghoul --- ext/ghoul | 2 +- modules/globebrowsing/chunk/chunkedlodglobe.cpp | 2 +- modules/globebrowsing/chunk/chunkrenderer.cpp | 4 ++-- modules/globebrowsing/chunk/culling.cpp | 2 +- modules/globebrowsing/globes/renderableglobe.cpp | 10 +++++----- modules/newhorizons/rendering/renderablefov.cpp | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ext/ghoul b/ext/ghoul index db86a30fd0..e45911445d 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit db86a30fd0f0aa1be9f3723a53acd7e85319e2a9 +Subproject commit e45911445d85b884baa017e175d6a175ca421d76 diff --git a/modules/globebrowsing/chunk/chunkedlodglobe.cpp b/modules/globebrowsing/chunk/chunkedlodglobe.cpp index 967bf6bac4..3996efb641 100644 --- a/modules/globebrowsing/chunk/chunkedlodglobe.cpp +++ b/modules/globebrowsing/chunk/chunkedlodglobe.cpp @@ -214,7 +214,7 @@ namespace openspace { const vec4& clippingSpaceCorner = mvp * modelSpaceCorners[i]; clippingSpaceCorners[i] = clippingSpaceCorner; - vec3 screenSpaceCorner = (1.0f / clippingSpaceCorner.w) * clippingSpaceCorner.xyz(); + vec3 screenSpaceCorner = (1.0f / clippingSpaceCorner.w) * clippingSpaceCorner; screenSpaceBounds.expand(screenSpaceCorner); } diff --git a/modules/globebrowsing/chunk/chunkrenderer.cpp b/modules/globebrowsing/chunk/chunkrenderer.cpp index c8315376b8..dd96239568 100644 --- a/modules/globebrowsing/chunk/chunkrenderer.cpp +++ b/modules/globebrowsing/chunk/chunkrenderer.cpp @@ -387,7 +387,7 @@ namespace openspace { glm::vec3 directionToSunWorldSpace = glm::normalize(-data.modelTransform.translation); glm::vec3 directionToSunCameraSpace = - (viewTransform * glm::dvec4(directionToSunWorldSpace, 0)).xyz(); + (viewTransform * glm::dvec4(directionToSunWorldSpace, 0)); data.modelTransform.translation; programObject->setUniform("modelViewTransform", modelViewTransform); programObject->setUniform("lightDirectionCameraSpace", -directionToSunCameraSpace); @@ -464,7 +464,7 @@ namespace openspace { glm::vec3 directionToSunWorldSpace = glm::normalize(-data.modelTransform.translation); glm::vec3 directionToSunCameraSpace = - (viewTransform * glm::dvec4(directionToSunWorldSpace, 0)).xyz(); + (viewTransform * glm::dvec4(directionToSunWorldSpace, 0)); data.modelTransform.translation; programObject->setUniform("lightDirectionCameraSpace", -directionToSunCameraSpace); } diff --git a/modules/globebrowsing/chunk/culling.cpp b/modules/globebrowsing/chunk/culling.cpp index 88a3d802dd..c281f6d7cb 100644 --- a/modules/globebrowsing/chunk/culling.cpp +++ b/modules/globebrowsing/chunk/culling.cpp @@ -72,7 +72,7 @@ namespace openspace { dvec4 cornerClippingSpace = modelViewProjectionTransform * corners[i]; clippingSpaceCorners[i] = cornerClippingSpace; - dvec3 cornerScreenSpace = (1.0f / glm::abs(cornerClippingSpace.w)) * cornerClippingSpace.xyz(); + dvec3 cornerScreenSpace = (1.0f / glm::abs(cornerClippingSpace.w)) * cornerClippingSpace; bounds.expand(cornerScreenSpace); } diff --git a/modules/globebrowsing/globes/renderableglobe.cpp b/modules/globebrowsing/globes/renderableglobe.cpp index d32146008d..8773d7ce37 100644 --- a/modules/globebrowsing/globes/renderableglobe.cpp +++ b/modules/globebrowsing/globes/renderableglobe.cpp @@ -234,14 +234,14 @@ namespace openspace { // Sample and do linear interpolation (could possibly be moved as a function in ghoul texture) glm::uvec3 dimensions = tile.texture->dimensions(); - glm::vec2 samplePos = transformedUv * glm::vec2(dimensions.xy()); + glm::vec2 samplePos = transformedUv * glm::vec2(dimensions); glm::uvec2 samplePos00 = samplePos; - samplePos00 = glm::clamp(samplePos00, glm::uvec2(0, 0), dimensions.xy() - glm::uvec2(1)); + samplePos00 = glm::clamp(samplePos00, glm::uvec2(0, 0), glm::uvec2(dimensions) - glm::uvec2(1)); glm::vec2 samplePosFract = samplePos - glm::vec2(samplePos00); - glm::uvec2 samplePos10 = glm::min(samplePos00 + glm::uvec2(1, 0), dimensions.xy() - glm::uvec2(1)); - glm::uvec2 samplePos01 = glm::min(samplePos00 + glm::uvec2(0, 1), dimensions.xy() - glm::uvec2(1)); - glm::uvec2 samplePos11 = glm::min(samplePos00 + glm::uvec2(1, 1), dimensions.xy() - glm::uvec2(1)); + glm::uvec2 samplePos10 = glm::min(samplePos00 + glm::uvec2(1, 0), glm::uvec2(dimensions) - glm::uvec2(1)); + glm::uvec2 samplePos01 = glm::min(samplePos00 + glm::uvec2(0, 1), glm::uvec2(dimensions) - glm::uvec2(1)); + glm::uvec2 samplePos11 = glm::min(samplePos00 + glm::uvec2(1, 1), glm::uvec2(dimensions) - glm::uvec2(1)); float sample00 = tile.texture->texelAsFloat(samplePos00).x; float sample10 = tile.texture->texelAsFloat(samplePos10).x; diff --git a/modules/newhorizons/rendering/renderablefov.cpp b/modules/newhorizons/rendering/renderablefov.cpp index a31acd90b7..878d833186 100644 --- a/modules/newhorizons/rendering/renderablefov.cpp +++ b/modules/newhorizons/rendering/renderablefov.cpp @@ -528,7 +528,7 @@ void RenderableFov::computeIntercepts(const RenderData& data) { _interceptTag[_bounds.size()] = _interceptTag[0]; fovSurfaceIntercept(_interceptTag, _bounds); - glm::vec3 aim = (_spacecraftRotation * glm::vec4(_boresight, 1)).xyz(); + glm::vec3 aim = (_spacecraftRotation * glm::vec4(_boresight, 1)); double lt; glm::dvec3 position = SpiceManager::ref().targetPosition( From 1b4b0f49b64a535c5fa1ed592ea3d801c05a296b Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Tue, 20 Sep 2016 10:11:59 +0200 Subject: [PATCH 91/92] Update SGCT --- ext/sgct | 2 +- modules/globebrowsing/tile/tiledataset.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ext/sgct b/ext/sgct index 8a1d737a80..9ad36dbaa5 160000 --- a/ext/sgct +++ b/ext/sgct @@ -1 +1 @@ -Subproject commit 8a1d737a8070a7c40c91d7bf24afa62feb73c8ea +Subproject commit 9ad36dbaa55d5267556a32338f8776a85c463321 diff --git a/modules/globebrowsing/tile/tiledataset.cpp b/modules/globebrowsing/tile/tiledataset.cpp index 161b37dc9f..4c2d0bc781 100644 --- a/modules/globebrowsing/tile/tiledataset.cpp +++ b/modules/globebrowsing/tile/tiledataset.cpp @@ -611,10 +611,10 @@ namespace openspace { } } - if (depth == 0) { - LDEBUG(indentation << "main rasterIO read: " << io.read.region); - LDEBUG(indentation << "main rasterIO write: " << io.write.region); - } + //if (depth == 0) { + //LDEBUG(indentation << "main rasterIO read: " << io.read.region); + //LDEBUG(indentation << "main rasterIO write: " << io.write.region); + //} else if (worstError > CPLErr::CE_None) { LDEBUG(indentation << "Error reading padding: " << worstError); From 7235df2fe3182e63973aae029560b2549acae5e8 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Tue, 20 Sep 2016 10:12:53 +0200 Subject: [PATCH 92/92] Place ScriptLog file in base directory --- openspace.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openspace.cfg b/openspace.cfg index 8ad6224f34..1af45848e7 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -51,7 +51,7 @@ return { }, ScriptLog = { Type = "text", - File = "${DOCUMENTATION}/ScriptLog.txt" + File = "${BASE_PATH}/ScriptLog.txt" }, KeyboardShortcuts = { Type = "html",