feat: add QBIN2 V4 encoded field ingress
Some checks failed
validate-scripts / validate-scripts (push) Has been cancelled
Some checks failed
validate-scripts / validate-scripts (push) Has been cancelled
This commit is contained in:
@@ -19,6 +19,7 @@ add_library(
|
||||
${PROJECT_SOURCE_DIR}/test/math/wrap.test.cpp
|
||||
${PROJECT_SOURCE_DIR}/test/platform/settings.test.cpp
|
||||
${PROJECT_SOURCE_DIR}/test/particle/field_runtime.test.cpp
|
||||
${PROJECT_SOURCE_DIR}/test/particle/qbin_v2_decoder.test.cpp
|
||||
${PROJECT_SOURCE_DIR}/test/plugin/plugin.test.cpp
|
||||
${PROJECT_SOURCE_DIR}/test/renderer/image_manager.test.cpp
|
||||
${PROJECT_SOURCE_DIR}/test/renderer/pattern_atlas.test.cpp
|
||||
|
||||
24
test/particle/qbin_v2_decoder.test.cpp
Normal file
24
test/particle/qbin_v2_decoder.test.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#include <mbgl/particle/ingress/qbin_v2_decoder.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
using namespace mbgl;
|
||||
namespace {
|
||||
void u16(std::vector<uint8_t>& b,size_t o,uint16_t v){b[o]=v;b[o+1]=v>>8;} void u32(std::vector<uint8_t>& b,size_t o,uint32_t v){for(int i=0;i<4;i++)b[o+i]=v>>(8*i);} void i64(std::vector<uint8_t>& b,size_t o,int64_t v){for(int i=0;i<8;i++)b[o+i]=uint64_t(v)>>(8*i);} template<class T> void fp(std::vector<uint8_t>& b,size_t o,T v){std::memcpy(b.data()+o,&v,sizeof v);} size_t a16(size_t x){return(x+15)&~size_t(15);}
|
||||
uint32_t crc(const std::vector<uint8_t>& b){uint32_t c=~0u;for(size_t i=0;i<b.size();++i){uint8_t x=i>=76&&i<80?0:b[i];c^=x;for(int j=0;j<8;j++)c=(c>>1)^((c&1)?0xedb88320u:0);}return~c;}
|
||||
struct P{uint16_t semantic=1,unit=1,group=1;uint8_t type=1,flags=1,vc=1,component=1;std::vector<uint8_t> raw;};
|
||||
std::vector<uint8_t> fixture(uint32_t w=2,uint32_t h=2,std::vector<P> ps={}) { if(ps.empty()) ps={{1,1,1,1,1,1,1,{1,0,2,0,3,0,4,0}},{2,1,1,1,1,1,2,{5,0,6,0,7,0,8,0}},{3,0,0,6,1,3,0,{15}}}; if(w*h!=4) for(auto& p:ps){p.raw.assign(p.type==6?(w*h+7)/8:(p.type==1||p.type==2?w*h*2:p.type==5?w*h*4:w*h),0);if(p.type==6)std::fill(p.raw.begin(),p.raw.end(),0xff),p.raw.back()=uint8_t((1u<<((w*h-1)%8+1))-1);} size_t po=112+ps.size()*32, off=0; for(auto&p:ps){off=a16(off+p.raw.size());} std::vector<uint8_t>b(po+off);std::memcpy(b.data(),"QBV2",4);b[4]=2;b[5]=1;u16(b,6,999);b[8]=b[9]=b[10]=1;u16(b,12,ps.size());u32(b,16,w);u32(b,20,h);i64(b,24,100);i64(b,32,90);fp(b,40,-10.);fp(b,48,-10.);fp(b,56,10.);fp(b,64,10.);u32(b,72,off);u16(b,80,0xffff);size_t cur=0;for(size_t i=0;i<ps.size();++i){auto&p=ps[i];size_t d=112+i*32;u16(b,d,p.semantic);b[d+2]=p.type;b[d+3]=p.flags;fp(b,d+4,p.type==6?1.f:.1f);fp(b,d+8,0.f);u32(b,d+12,w*h);u32(b,d+16,cur);u32(b,d+20,p.raw.size());u16(b,d+24,p.unit);u16(b,d+26,p.group);b[d+28]=p.vc;b[d+29]=p.component;std::memcpy(b.data()+po+cur,p.raw.data(),p.raw.size());cur=a16(cur+p.raw.size());}u32(b,76,crc(b));return b;}
|
||||
void recalc(std::vector<uint8_t>& b){u32(b,76,crc(b));}
|
||||
particle::ingress::EncodedFieldRuntimeMetadata meta(){return{"field",1,7};}
|
||||
particle::ResolvedFieldProfileContract wind(){particle::ResolvedFieldProfileContract c; c.profileID="generic.wind";c.profileVersion=1;c.requiredPlanes={{1,particle::FieldValueClass::VelocityComponent,1,1,particle::FieldComponent::UEast,true},{2,particle::FieldValueClass::VelocityComponent,1,1,particle::FieldComponent::VNorth,true},{3,particle::FieldValueClass::Validity,0,0,particle::FieldComponent::None,true}};return c;}
|
||||
}
|
||||
TEST(ParticleQbinV2Decoder, DecodesGenericFrameAndSharesValidity) {auto r=particle::ingress::QbinV2Decoder::decode(meta(),fixture());ASSERT_TRUE(r.accepted())<<r.detail;EXPECT_EQ(r.frame->referenceTimeMs,100000);EXPECT_EQ(r.frame->frameContentIdentity.validTimeMs,90000);EXPECT_EQ(r.frame->planes.size(),2);EXPECT_EQ(r.frame->validityPlane.storage,r.frame->validityBits);}
|
||||
TEST(ParticleQbinV2Decoder, RejectsStructuralAndCrcViolations) {auto b=fixture();b[0]='X';EXPECT_EQ(particle::ingress::QbinV2Decoder::decode(meta(),b).code,particle::ingress::QbinV2DecodeErrorCode::BadMagic);b=fixture();b[11]=1;recalc(b);EXPECT_EQ(particle::ingress::QbinV2Decoder::decode(meta(),b).code,particle::ingress::QbinV2DecodeErrorCode::ReservedNonZero);b=fixture();b[208]^=1;EXPECT_EQ(particle::ingress::QbinV2Decoder::decode(meta(),b).code,particle::ingress::QbinV2DecodeErrorCode::CrcMismatch);}
|
||||
TEST(ParticleQbinV2Decoder, RejectsValidityAndInvalidCells) {auto b=fixture();size_t po=208;b[po+32]=0x0e;recalc(b);EXPECT_EQ(particle::ingress::QbinV2Decoder::decode(meta(),b).code,particle::ingress::QbinV2DecodeErrorCode::InvalidCellPayload);b=fixture();b[po+32]=0xf0;recalc(b);EXPECT_EQ(particle::ingress::QbinV2Decoder::decode(meta(),b).code,particle::ingress::QbinV2DecodeErrorCode::InvalidValidity);}
|
||||
TEST(ParticleQbinV2Decoder, PlaneContentIdentityIsIndependent) {auto a=fixture();auto b=a;b[208+16]=9;recalc(b);auto ra=particle::ingress::QbinV2Decoder::decode(meta(),a);auto rb=particle::ingress::QbinV2Decoder::decode(meta(),b);ASSERT_TRUE(ra.accepted());ASSERT_TRUE(rb.accepted());EXPECT_EQ(ra.frame->planes[0].contentIdentity,rb.frame->planes[0].contentIdentity);EXPECT_NE(ra.frame->planes[1].contentIdentity,rb.frame->planes[1].contentIdentity);}
|
||||
TEST(ParticleQbinV2Decoder, DecodesLargeStructuralFixture) {auto r=particle::ingress::QbinV2Decoder::decode(meta(),fixture(513,769));ASSERT_TRUE(r.accepted())<<r.detail;EXPECT_EQ(r.frame->grid.width,513);EXPECT_EQ(r.frame->grid.height,769);EXPECT_EQ(r.frame->planes[0].storage->size(),513u*769u*2u);}
|
||||
TEST(ParticleEncodedFieldIngress, ValidatesContractAndReportsMissing) {auto good=wind();auto ok=particle::ingress::EncodedFieldIngress::decodeAndValidate(meta(),&good,fixture());EXPECT_TRUE(ok.accepted());auto miss=particle::ingress::EncodedFieldIngress::decodeAndValidate(meta(),nullptr,fixture());EXPECT_EQ(miss.code,particle::ingress::EncodedFieldIngressCode::ContractMissing);auto c=wind();c.requiredPlanes.pop_back();auto bad=particle::ingress::EncodedFieldIngress::decodeAndValidate(meta(),&c,fixture());EXPECT_EQ(bad.code,particle::ingress::EncodedFieldIngressCode::ContractRejected);}
|
||||
Reference in New Issue
Block a user