/** * Copyright - See the COPYRIGHT that is included with this distribution. * pvxs is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. */ #include #include #include #include #include #include #include "utilpvt.h" #include #include #include namespace { using namespace pvxs; template void testEmpty() { testDiag("%s", __func__); shared_array v; testOk1(v.unique()); testOk1(v.empty()); testEq(v.size(), 0u); } template void testInt() { testDiag("%s w/ %s", __func__, typeid(I).name()); shared_array X(2, 5); testOk1(X.unique()); testOk1(!X.empty()); if(testEq(X.size(), 2u)) { testEq(X[0], 5); testEq(X[1], 5); } shared_array Y(X); testOk1(!X.unique()); testOk1(!Y.unique()); testEq(X.size(), Y.size()); X.clear(); testOk1(X.unique()); testOk1(Y.unique()); testEq(X.size(), 0u); testEq(Y.size(), 2u); X = std::move(Y); testOk1(X.unique()); testOk1(Y.unique()); testEq(X.size(), 2u); testEq(Y.size(), 0u); shared_array Z(std::move(X)); testOk1(X.unique()); testOk1(Y.unique()); testOk1(Z.unique()); testEq(X.size(), 0u); testEq(Y.size(), 0u); testEq(Z.size(), 2u); // copy empty shared_array Q(Y); testOk1(Y.unique()); testOk1(Q.unique()); testEq(Y.size(), 0u); testEq(Q.size(), 0u); } template void testVoid() { testDiag("%s", __func__); shared_array X(2); shared_array Y(X.template castTo()); testOk1(!X.unique()); testOk1(!Y.unique()); testEq(X.size(), 2u); testEq(Y.size(), 2u); testEq(Y.original_type(), ArrayType::UInt32); // never const uint32_t testThrows([&Y]() { auto Z = Y.freeze(); }); X.clear(); testOk1(Y.unique()); auto Z = Y.freeze(); testOk1(Y.unique()); testOk1(Z.unique()); testEq(Y.size(), 0u); testEq(Z.size(), 2u); } template void testVoidAssemble() { testDiag("%s", __func__); pvxs::ArrayType code = pvxs::detail::CaptureBase::code; auto temp = (typename std::remove_cv::type*)calloc(3, sizeof(I)); if(!temp) testAbort("calloc failure"); temp[0] = 1; temp[1] = 2; temp[2] = 3; pvxs::shared_array X((Void*)temp, [](Void *p) { free((void*)p); }, 3u, code); testEq(temp, X.data()); testEq(code, X.original_type()); testEq(3u, X.size()); auto Y(X.template castTo()); testEq(temp, Y.data()); testEq(3u, Y.size()); testEq(Y[0], 1u); } void testFreeze() { testDiag("%s", __func__); shared_array X(2, 5); shared_array Y(X.freeze()); testOk1(X.unique()); testOk1(Y.unique()); testEq(X.size(), 0u); testEq(Y.size(), 2u); } void testFreezeError() { testDiag("%s", __func__); shared_array X(2, 5), Z(X); testOk1(!X.unique()); testThrows([&X]() { shared_array Y(X.freeze()); })<<"Attempt to freeze() non-unique"; } void testThaw() { testDiag("%s", __func__); shared_array X({2, 5}), Y(X), Z({4, 5}); auto saveX = X.data(); auto saveZ = Z.data(); auto A(X.thaw()); // copies auto B(Y.thaw()); // casts auto C(Z.thaw()); // casts testOk1(A.unique()); testOk1(B.unique()); testOk1(C.unique()); testEq(A.size(), 2u); testEq(B.size(), 2u); testEq(C.size(), 2u); testEq(X.size(), 0u); testEq(Y.size(), 0u); testEq(Z.size(), 0u); testNotEq(A.data(), saveX); testEq (B.data(), saveX); testEq (C.data(), saveZ); testEq(A[0], 2u); testEq(B[0], 2u); testEq(C[0], 4u); } void testFreezeThawVoid() { testDiag("%s", __func__); shared_array A(2, 5); auto saveA = A.data(); auto vA(A.castTo()); A.clear(); auto cvB(vA.freeze()); testEq(vA.size(), 0u); testEq(cvB.size(), 2u); testEq(cvB.original_type(), ArrayType::UInt32); testTrue(cvB.unique()); auto cvC(cvB); auto vB(cvB.thaw()); // copy testTrue(cvC.unique()); auto vC(cvC.thaw()); // cast testEq(cvB.size(), 0u); testEq(cvC.size(), 0u); testEq(vB.size(), 2u); testEq(vC.size(), 2u); testNotEq(vB.data(), saveA); testEq (vC.data(), saveA); auto B(vB.castTo()); auto C(vC.castTo()); testEq(B[0], 5u); testEq(C[0], 5u); } struct ImMobile { int v = 0; ImMobile() = default; void store(int x) { v=x; } int load() const { return v; } ImMobile(const ImMobile&) = delete; ImMobile(ImMobile&&) = delete; ImMobile& operator=(const ImMobile&) = delete; ImMobile& operator=(ImMobile&&) = delete; }; void testComplex() { testDiag("%s", __func__); shared_array X(2); X[0].store(4); testEq(X[0].load(), 4); } void testValue() { testDiag("%s", __func__); auto top = TypeDef(TypeCode::UInt32).create(); shared_array A(allocArray(ArrayType::Value, 2u).castTo()); A[0] = top.cloneEmpty(); A[0] = 1u; A[1] = top.cloneEmpty(); A[1] = 2u; auto varr(A.castTo()); testEq(varr.size(), 2u); testEq(varr.original_type(), ArrayType::Value); auto B(varr.castTo()); testEq(B.size(), 2u); testEq(B.at(0).as(), 1u); testEq(B.at(1).as(), 2u); } void testCast() { testDiag("%s", __func__); shared_array Void; (void)Void.castTo(); (void)Void.castTo(); // not allowed //(void)Void.castTo(); //(void)Void.castTo(); shared_array CVoid; (void)CVoid.castTo(); (void)CVoid.castTo(); // not allowed //(void)CVoid.castTo(); //(void)CVoid.castTo(); shared_array Int; (void)Int.castTo(); (void)Int.castTo(); // not allowed //(void)Int.castTo(); //(void)Int.castTo(); shared_array CInt; (void)CInt.castTo(); (void)CInt.castTo(); // not allowed //(void)CInt.castTo(); //(void)CInt.castTo(); shared_array Double({1.0, 2.0}); Void = Double.castTo(); testThrows([&Void](){ (void)Void.castTo(); })<<"Attempt cast to wrong type"; Void.clear(); // now doesn't throw (void)Void.castTo(); } void testFromVector() { testDiag("%s", __func__); std::vector V({1, 2, 3}); shared_array A(V.begin(), V.end()); testEq(A.size(), 3u); testEq(A.at(2), 3u); // not consumed testEq(V.size(), 3u); } void testElemAlloc() { testDiag("%s", __func__); testEq(elementSize(ArrayType::UInt8), 1u); testEq(elementSize(ArrayType::UInt16), 2u); testEq(elementSize(ArrayType::UInt32), 4u); testEq(elementSize(ArrayType::UInt64), 8u); auto varr = allocArray(ArrayType::UInt32, 3u); testEq(varr.size(), 3u); testEq(varr.original_type(), ArrayType::UInt32); } // round trip conversion when TO can exactly represent all possible values of FROM template void testConvertExact() { shared_array inp({ FROM(0), FROM(1), FROM(-1), std::numeric_limits::min(), std::numeric_limits::max(), }); shared_array expect({ (TO)FROM(0), (TO)FROM(1), (TO)FROM(-1), (TO)std::numeric_limits::min(), (TO)std::numeric_limits::max(), }); auto conv(inp.template convertTo()); testShow()<<"Input "< "<(), inp)<<" "<<__func__<<"("< void testConvertTrunc() { shared_array inp({ FROM(0), FROM(1), FROM(-1), std::numeric_limits::min(), std::numeric_limits::max(), }); shared_array expect({ (TO)FROM(0), (TO)FROM(1), (TO)FROM(-1), (TO)std::numeric_limits::min(), (TO)std::numeric_limits::max(), }); auto conv(inp.template convertTo()); testShow()<<"Input "< "< void testToFromString() { shared_array inp({ T(0), T(1), T(-1), std::numeric_limits::min(), std::numeric_limits::max(), }); shared_array expect({ (SB()<::op(T(0))).str(), (SB()<::op(T(1))).str(), (SB()<::op(T(-1))).str(), (SB()<::op(std::numeric_limits::min())).str(), (SB()<::op(std::numeric_limits::max())).str(), }); testShow()<<"Input "<()); testArrEq(conv, expect)<<" "<<__func__<<"("< str)"; }catch(std::exception& e){ testFail("%s(%s -> str) throws %s", __func__, typeid(T).name(), e.what()); } try{ testArrEq(expect.template convertTo(), inp)<<" "<<__func__<<"("<::code!=detail::CaptureCode::code, ""); testDiag("reversible conversions"); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testConvertExact(); testDiag("integer truncation"); testConvertTrunc(); testConvertTrunc(); testConvertTrunc(); testConvertTrunc(); testConvertTrunc(); testConvertTrunc(); testToFromString(); testToFromString(); testToFromString(); testToFromString(); testToFromString(); testToFromString(); testToFromString(); testToFromString(); testTodoBegin("problems parsing +-DBL/FLT_MIN/MAX"); testToFromString(); testToFromString(); testTodoEnd(); testArrEq(shared_array({true, false}).convertTo(), shared_array({"true", "false"})); testArrEq(shared_array({1u, 2u, 0xffffffffu}).convertTo(), shared_array({1u, 2u, 0xffffffffu})); testArrEq(shared_array({1u, 2u, 0xffffffffu}).convertTo(), shared_array({1u, 2u, 0xffffu})); testArrEq(shared_array({1u, 2u, 0xffffffffu}).convertTo(), shared_array({1, 2, -1})); testArrEq(shared_array({1u, 2u, 0xffffffffu}).convertTo(), shared_array({1, 2, -1})); testArrEq(shared_array({1, 2, -1}).convertTo(), shared_array({1u, 2u, 0xffffffffu})); testArrEq(shared_array({1, 2, -1}).convertTo(), shared_array({1.0, 2.0, -1.0})); testArrEq(shared_array({1, 2, -1}).convertTo(), shared_array({"1", "2", "-1"})); } } // namespace MAIN(testshared) { testPlan(268); testSetup(); testEmpty(); testEmpty(); testEmpty(); testEmpty(); testInt(); testInt(); testVoid(); testVoid(); testVoidAssemble(); testVoidAssemble(); testFreeze(); testFreezeError(); testThaw(); testFreezeThawVoid(); testComplex(); testValue(); testCast(); testFromVector(); testElemAlloc(); testConvert(); return testDone(); }