From 65c742b67a9f50c7f4f8203699ed73101615f959 Mon Sep 17 00:00:00 2001
From: Haocheng Liu <haocheng.liu@kitware.com>
Date: Thu, 31 Aug 2017 14:42:40 -0400
Subject: [PATCH] Testing: Make ADIOSDefineAttribute able to run in parallel

---
 .../engine/bp/TestBPWriteReadAttributes.cpp   |   2 +-
 testing/adios2/interface/CMakeLists.txt       |  18 +-
 .../interface/TestADIOSDefineAttribute.cpp    | 910 +++++++++---------
 3 files changed, 454 insertions(+), 476 deletions(-)

diff --git a/testing/adios2/engine/bp/TestBPWriteReadAttributes.cpp b/testing/adios2/engine/bp/TestBPWriteReadAttributes.cpp
index b963ad7a3..d2bb5bfed 100644
--- a/testing/adios2/engine/bp/TestBPWriteReadAttributes.cpp
+++ b/testing/adios2/engine/bp/TestBPWriteReadAttributes.cpp
@@ -57,7 +57,7 @@ TEST_F(BPWriteReadAttributeTest, ADIOS2BPWriteADIOS1ReadSingleTypes)
     std::string double_Single = std::string("double_Single_") + mpiRankString;
 
     // When collective meta generation has landed, use
-    // generateNewSmallTestData(m_TestData, 0, 0, mpiSize);
+    // generateNewSmallTestData(m_TestData, 0, mpiRank, mpiSize);
     // Generate current testing data
     SmallTestData currentTestData =
         generateNewSmallTestData(m_TestData, 0, 0, 0);
diff --git a/testing/adios2/interface/CMakeLists.txt b/testing/adios2/interface/CMakeLists.txt
index c446f5eef..14657a05c 100644
--- a/testing/adios2/interface/CMakeLists.txt
+++ b/testing/adios2/interface/CMakeLists.txt
@@ -12,6 +12,22 @@ target_link_libraries(TestADIOSDefineVariable adios2 gtest gtest_main)
 add_executable(TestADIOSDefineAttribute TestADIOSDefineAttribute.cpp)
 target_link_libraries(TestADIOSDefineAttribute adios2 gtest gtest_main)
 
+if(ADIOS2_HAVE_MPI)
+  target_include_directories(TestADIOSInterfaceWrite PRIVATE ${MPI_C_INCLUDE_PATH})
+  target_link_libraries(TestADIOSInterfaceWrite ${MPI_C_LIBRARIES})
+
+  target_include_directories(TestADIOSDefineVariable PRIVATE ${MPI_C_INCLUDE_PATH})
+  target_link_libraries(TestADIOSDefineVariable ${MPI_C_LIBRARIES})
+
+  target_include_directories(TestADIOSDefineAttribute PRIVATE ${MPI_C_INCLUDE_PATH})
+  target_link_libraries(TestADIOSDefineAttribute ${MPI_C_LIBRARIES})
+
+  set(extra_test_args
+    EXEC_WRAPPER
+      ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 2#${MPIEXEC_MAX_NUMPROCS}
+  )
+endif()
+
 gtest_add_tests(TARGET TestADIOSInterfaceWrite)
 gtest_add_tests(TARGET TestADIOSDefineVariable)
-gtest_add_tests(TARGET TestADIOSDefineAttribute)
\ No newline at end of file
+gtest_add_tests(TARGET TestADIOSDefineAttribute ${extra_test_args})
diff --git a/testing/adios2/interface/TestADIOSDefineAttribute.cpp b/testing/adios2/interface/TestADIOSDefineAttribute.cpp
index 3471ac750..7fc73d6f9 100644
--- a/testing/adios2/interface/TestADIOSDefineAttribute.cpp
+++ b/testing/adios2/interface/TestADIOSDefineAttribute.cpp
@@ -7,11 +7,15 @@
 
 #include <gtest/gtest.h>
 
+#include "../engine/SmallTestData.h"
+
 class ADIOSDefineAttributeTest : public ::testing::Test
 {
 public:
     ADIOSDefineAttributeTest() : adios(true), io(adios.DeclareIO("TestIO")) {}
 
+    SmallTestData m_TestData;
+
 protected:
     adios2::ADIOS adios;
     adios2::IO &io;
@@ -19,6 +23,7 @@ protected:
 
 TEST_F(ADIOSDefineAttributeTest, DefineAttributeNameException)
 {
+    // Attribute should be unique per process
     auto &attributeString1 =
         io.DefineAttribute<std::string>("attributeString", "-1");
 
@@ -36,538 +41,495 @@ TEST_F(ADIOSDefineAttributeTest, DefineAttributeNameException)
 
 TEST_F(ADIOSDefineAttributeTest, DefineAttributeTypeByValue)
 {
+
+    int mpiRank = 0, mpiSize = 1;
+#ifdef ADIOS2_HAVE_MPI
+    MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
+    MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
+#endif
+
+    // Define unique data for each process
+    SmallTestData currentTestData =
+        generateNewSmallTestData(m_TestData, 0, mpiRank, mpiSize);
+
+    std::string mpiRankString = std::to_string(mpiRank);
+    std::string s1_Single = std::string("s1_Single_") + mpiRankString;
+    std::string i8_Single = std::string("i8_Single_") + mpiRankString;
+    std::string i16_Single = std::string("i16_Single_") + mpiRankString;
+    std::string i32_Single = std::string("i32_Single_") + mpiRankString;
+    std::string i64_Single = std::string("i64_Single_") + mpiRankString;
+    std::string u8_Single = std::string("u8_Single_") + mpiRankString;
+    std::string u16_Single = std::string("u16_Single_") + mpiRankString;
+    std::string u32_Single = std::string("u32_Single_") + mpiRankString;
+    std::string u64_Single = std::string("u64_Single_") + mpiRankString;
+    std::string float_Single = std::string("float_Single_") + mpiRankString;
+    std::string double_Single = std::string("double_Single_") + mpiRankString;
+
     // Define ADIOS global value
-    auto &attributeString =
-        io.DefineAttribute<std::string>("attributeString", "-1");
-    auto &attributeChar = io.DefineAttribute<char>("attributeChar", '0');
-    auto &attributeUChar =
-        io.DefineAttribute<unsigned char>("attributeUChar", '1');
-    auto &attributeShort = io.DefineAttribute<short>("attributeShort", 2);
-    auto &attributeUShort =
-        io.DefineAttribute<unsigned short>("attributeUShort", 3);
-    auto &attributeInt = io.DefineAttribute<int>("attributeInt", 4);
-    auto &attributeUInt = io.DefineAttribute<unsigned int>("attributeUInt", 5);
-    auto &attributeLInt = io.DefineAttribute<long int>("attributeLInt", 6);
-    auto &attributeULInt =
-        io.DefineAttribute<unsigned long int>("attributeULInt", 7);
-    auto &attributeLLInt =
-        io.DefineAttribute<long long int>("attributeLLInt", 8);
-    auto &attributeULLInt =
-        io.DefineAttribute<unsigned long long int>("attributeULLInt", 9);
-    auto &attributeFloat = io.DefineAttribute<float>("attributeFloat", 10);
-    auto &attributeDouble = io.DefineAttribute<double>("attributeDouble", 11);
-    auto &attributeLDouble =
-        io.DefineAttribute<long double>("attributeLDouble", 12);
+    auto &attributeS1 =
+        io.DefineAttribute<std::string>(s1_Single, currentTestData.S1);
+    auto &attributeI8 =
+        io.DefineAttribute<int8_t>(i8_Single, currentTestData.I8.front());
+    auto &attributeI16 =
+        io.DefineAttribute<int16_t>(i16_Single, currentTestData.I16.front());
+    auto &attributeI32 =
+        io.DefineAttribute<int32_t>(i32_Single, currentTestData.I32.front());
+    auto &attributeI64 =
+        io.DefineAttribute<int64_t>(i64_Single, currentTestData.I64.front());
+
+    auto &attributeU8 =
+        io.DefineAttribute<uint8_t>(u8_Single, currentTestData.U8.front());
+    auto &attributeU16 =
+        io.DefineAttribute<uint16_t>(u16_Single, currentTestData.U16.front());
+    auto &attributeU32 =
+        io.DefineAttribute<uint32_t>(u32_Single, currentTestData.U32.front());
+    auto &attributeU64 =
+        io.DefineAttribute<uint64_t>(u64_Single, currentTestData.U64.front());
+
+    auto &attributeFloat =
+        io.DefineAttribute<float>(float_Single, currentTestData.R32.front());
+    auto &attributeDouble =
+        io.DefineAttribute<double>(double_Single, currentTestData.R64.front());
 
     // Verify the return type is as expected
-    ::testing::StaticAssertTypeEq<decltype(attributeString),
+    ::testing::StaticAssertTypeEq<decltype(attributeS1),
                                   adios2::Attribute<std::string> &>();
-    ::testing::StaticAssertTypeEq<decltype(attributeChar),
-                                  adios2::Attribute<char> &>();
-    ::testing::StaticAssertTypeEq<decltype(attributeUChar),
-                                  adios2::Attribute<unsigned char> &>();
-    ::testing::StaticAssertTypeEq<decltype(attributeShort),
-                                  adios2::Attribute<short> &>();
-    ::testing::StaticAssertTypeEq<decltype(attributeUShort),
-                                  adios2::Attribute<unsigned short> &>();
-    ::testing::StaticAssertTypeEq<decltype(attributeInt),
-                                  adios2::Attribute<int> &>();
-    ::testing::StaticAssertTypeEq<decltype(attributeUInt),
-                                  adios2::Attribute<unsigned int> &>();
-    ::testing::StaticAssertTypeEq<decltype(attributeLInt),
-                                  adios2::Attribute<long int> &>();
-    ::testing::StaticAssertTypeEq<decltype(attributeULInt),
-                                  adios2::Attribute<unsigned long int> &>();
-    ::testing::StaticAssertTypeEq<decltype(attributeLLInt),
-                                  adios2::Attribute<long long int> &>();
-    ::testing::StaticAssertTypeEq<
-        decltype(attributeULLInt),
-        adios2::Attribute<unsigned long long int> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeI8),
+                                  adios2::Attribute<int8_t> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeI16),
+                                  adios2::Attribute<int16_t> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeI32),
+                                  adios2::Attribute<int32_t> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeI64),
+                                  adios2::Attribute<int64_t> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeU8),
+                                  adios2::Attribute<uint8_t> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeU16),
+                                  adios2::Attribute<uint16_t> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeU32),
+                                  adios2::Attribute<uint32_t> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeU64),
+                                  adios2::Attribute<uint64_t> &>();
     ::testing::StaticAssertTypeEq<decltype(attributeFloat),
                                   adios2::Attribute<float> &>();
     ::testing::StaticAssertTypeEq<decltype(attributeDouble),
                                   adios2::Attribute<double> &>();
-    ::testing::StaticAssertTypeEq<decltype(attributeLDouble),
-                                  adios2::Attribute<long double> &>();
 
     // Verify the members are correct
-    ASSERT_EQ(attributeString.m_IsSingleValue, true);
-    EXPECT_EQ(attributeString.m_Name, "attributeString");
-    EXPECT_EQ(attributeString.m_DataSingleValue, "-1");
-    EXPECT_EQ(attributeString.m_Elements, 1);
-    EXPECT_EQ(attributeString.m_Type, "string");
-
-    ASSERT_EQ(attributeChar.m_DataArray.empty(), true);
-    EXPECT_EQ(attributeChar.m_Name, "attributeChar");
-    EXPECT_EQ(attributeChar.m_DataSingleValue, '0');
-    EXPECT_EQ(attributeChar.m_Elements, 1);
-    EXPECT_EQ(attributeChar.m_Type, "char");
-
-    ASSERT_EQ(attributeUChar.m_DataArray.empty(), true);
-    EXPECT_EQ(attributeUChar.m_Name, "attributeUChar");
-    EXPECT_EQ(attributeUChar.m_DataSingleValue, '1');
-    EXPECT_EQ(attributeUChar.m_Elements, 1);
-    EXPECT_EQ(attributeUChar.m_Type, "unsigned char");
-
-    ASSERT_EQ(attributeShort.m_DataArray.empty(), true);
-    EXPECT_EQ(attributeShort.m_Name, "attributeShort");
-    EXPECT_EQ(attributeShort.m_DataSingleValue, 2);
-    EXPECT_EQ(attributeShort.m_Elements, 1);
-    EXPECT_EQ(attributeShort.m_Type, "short");
-
-    ASSERT_EQ(attributeUShort.m_DataArray.empty(), true);
-    EXPECT_EQ(attributeUShort.m_Name, "attributeUShort");
-    EXPECT_EQ(attributeUShort.m_DataSingleValue, 3);
-    EXPECT_EQ(attributeUShort.m_Elements, 1);
-    EXPECT_EQ(attributeUShort.m_Type, "unsigned short");
-
-    ASSERT_EQ(attributeInt.m_DataArray.empty(), true);
-    EXPECT_EQ(attributeInt.m_Name, "attributeInt");
-    EXPECT_EQ(attributeInt.m_DataSingleValue, 4);
-    EXPECT_EQ(attributeInt.m_Elements, 1);
-    EXPECT_EQ(attributeInt.m_Type, "int");
-
-    ASSERT_EQ(attributeUInt.m_DataArray.empty(), true);
-    EXPECT_EQ(attributeUInt.m_Name, "attributeUInt");
-    EXPECT_EQ(attributeUInt.m_DataSingleValue, 5);
-    EXPECT_EQ(attributeUInt.m_Elements, 1);
-    EXPECT_EQ(attributeUInt.m_Type, "unsigned int");
-
-    ASSERT_EQ(attributeLInt.m_DataArray.empty(), true);
-    EXPECT_EQ(attributeLInt.m_Name, "attributeLInt");
-    EXPECT_EQ(attributeLInt.m_DataSingleValue, 6);
-    EXPECT_EQ(attributeLInt.m_Elements, 1);
-    EXPECT_EQ(attributeLInt.m_Type, "long int");
-
-    ASSERT_EQ(attributeULInt.m_DataArray.empty(), true);
-    EXPECT_EQ(attributeULInt.m_Name, "attributeULInt");
-    EXPECT_EQ(attributeULInt.m_DataSingleValue, 7);
-    EXPECT_EQ(attributeULInt.m_Elements, 1);
-    EXPECT_EQ(attributeULInt.m_Type, "unsigned long int");
-
-    ASSERT_EQ(attributeLLInt.m_DataArray.empty(), true);
-    EXPECT_EQ(attributeLLInt.m_Name, "attributeLLInt");
-    EXPECT_EQ(attributeLLInt.m_DataSingleValue, 8);
-    EXPECT_EQ(attributeLLInt.m_Elements, 1);
-    EXPECT_EQ(attributeLLInt.m_Type, "long long int");
-
-    ASSERT_EQ(attributeULLInt.m_DataArray.empty(), true);
-    EXPECT_EQ(attributeULLInt.m_Name, "attributeULLInt");
-    EXPECT_EQ(attributeULLInt.m_DataSingleValue, 9);
-    EXPECT_EQ(attributeULLInt.m_Elements, 1);
-    EXPECT_EQ(attributeULLInt.m_Type, "unsigned long long int");
-
+    ASSERT_EQ(attributeS1.m_IsSingleValue, true);
+    ASSERT_EQ(attributeS1.m_DataArray.empty(), true);
+    EXPECT_EQ(attributeS1.m_Name, s1_Single);
+    EXPECT_EQ(attributeS1.m_DataSingleValue, currentTestData.S1);
+    EXPECT_EQ(attributeS1.m_Elements, 1);
+    EXPECT_EQ(attributeS1.m_Type, "string");
+
+    ASSERT_EQ(attributeI8.m_IsSingleValue, true);
+    ASSERT_EQ(attributeI8.m_DataArray.empty(), true);
+    EXPECT_EQ(attributeI8.m_Name, i8_Single);
+    EXPECT_EQ(attributeI8.m_DataSingleValue, currentTestData.I8.front());
+    EXPECT_EQ(attributeI8.m_Elements, 1);
+    EXPECT_EQ(attributeI8.m_Type, "signed char");
+
+    ASSERT_EQ(attributeI16.m_IsSingleValue, true);
+    ASSERT_EQ(attributeI16.m_DataArray.empty(), true);
+    EXPECT_EQ(attributeI16.m_Name, i16_Single);
+    EXPECT_EQ(attributeI16.m_DataSingleValue, currentTestData.I16.front());
+    EXPECT_EQ(attributeI16.m_Elements, 1);
+    EXPECT_EQ(attributeI16.m_Type, "short");
+
+    ASSERT_EQ(attributeI32.m_IsSingleValue, true);
+    ASSERT_EQ(attributeI32.m_DataArray.empty(), true);
+    EXPECT_EQ(attributeI32.m_Name, i32_Single);
+    EXPECT_EQ(attributeI32.m_DataSingleValue, currentTestData.I32.front());
+    EXPECT_EQ(attributeI32.m_Elements, 1);
+    EXPECT_EQ(attributeI32.m_Type, "int");
+
+    ASSERT_EQ(attributeI64.m_IsSingleValue, true);
+    ASSERT_EQ(attributeI64.m_DataArray.empty(), true);
+    EXPECT_EQ(attributeI64.m_Name, i64_Single);
+    EXPECT_EQ(attributeI64.m_DataSingleValue, currentTestData.I64.front());
+    EXPECT_EQ(attributeI64.m_Elements, 1);
+    EXPECT_EQ(attributeI64.m_Type, "long int");
+
+    ASSERT_EQ(attributeU8.m_IsSingleValue, true);
+    ASSERT_EQ(attributeU8.m_DataArray.empty(), true);
+    EXPECT_EQ(attributeU8.m_Name, u8_Single);
+    EXPECT_EQ(attributeU8.m_DataSingleValue, currentTestData.U8.front());
+    EXPECT_EQ(attributeU8.m_Elements, 1);
+    EXPECT_EQ(attributeU8.m_Type, "unsigned char");
+
+    ASSERT_EQ(attributeU16.m_IsSingleValue, true);
+    ASSERT_EQ(attributeU16.m_DataArray.empty(), true);
+    EXPECT_EQ(attributeU16.m_Name, u16_Single);
+    EXPECT_EQ(attributeU16.m_DataSingleValue, currentTestData.U16.front());
+    EXPECT_EQ(attributeU16.m_Elements, 1);
+    EXPECT_EQ(attributeU16.m_Type, "unsigned short");
+
+    ASSERT_EQ(attributeU32.m_IsSingleValue, true);
+    ASSERT_EQ(attributeU32.m_DataArray.empty(), true);
+    EXPECT_EQ(attributeU32.m_Name, u32_Single);
+    EXPECT_EQ(attributeU32.m_DataSingleValue, currentTestData.U32.front());
+    EXPECT_EQ(attributeU32.m_Elements, 1);
+    EXPECT_EQ(attributeU32.m_Type, "unsigned int");
+
+    ASSERT_EQ(attributeU64.m_IsSingleValue, true);
+    ASSERT_EQ(attributeU64.m_DataArray.empty(), true);
+    EXPECT_EQ(attributeU64.m_Name, u64_Single);
+    EXPECT_EQ(attributeU64.m_DataSingleValue, currentTestData.U64.front());
+    EXPECT_EQ(attributeU64.m_Elements, 1);
+    EXPECT_EQ(attributeU64.m_Type, "unsigned long int");
+
+    ASSERT_EQ(attributeFloat.m_IsSingleValue, true);
     ASSERT_EQ(attributeFloat.m_DataArray.empty(), true);
-    EXPECT_EQ(attributeFloat.m_Name, "attributeFloat");
-    EXPECT_EQ(attributeFloat.m_DataSingleValue, 10);
+    EXPECT_EQ(attributeFloat.m_Name, float_Single);
+    EXPECT_EQ(attributeFloat.m_DataSingleValue, currentTestData.R32.front());
     EXPECT_EQ(attributeFloat.m_Elements, 1);
     EXPECT_EQ(attributeFloat.m_Type, "float");
 
+    ASSERT_EQ(attributeDouble.m_IsSingleValue, true);
     ASSERT_EQ(attributeDouble.m_DataArray.empty(), true);
-    EXPECT_EQ(attributeDouble.m_Name, "attributeDouble");
-    EXPECT_EQ(attributeDouble.m_DataSingleValue, 11);
+    EXPECT_EQ(attributeDouble.m_Name, double_Single);
+    EXPECT_EQ(attributeDouble.m_DataSingleValue, currentTestData.R64.front());
     EXPECT_EQ(attributeDouble.m_Elements, 1);
     EXPECT_EQ(attributeDouble.m_Type, "double");
-
-    ASSERT_EQ(attributeLDouble.m_DataArray.empty(), true);
-    EXPECT_EQ(attributeLDouble.m_Name, "attributeLDouble");
-    EXPECT_EQ(attributeLDouble.m_DataSingleValue, 12);
-    EXPECT_EQ(attributeLDouble.m_Elements, 1);
-    EXPECT_EQ(attributeLDouble.m_Type, "long double");
 }
 
 TEST_F(ADIOSDefineAttributeTest, DefineAttributeTypeByReference)
 {
+    int mpiRank = 0, mpiSize = 1;
+    size_t numberOfElements = 10;
+#ifdef ADIOS2_HAVE_MPI
+    MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
+    MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
+#endif
+
+    // Define unique data for each process
+    SmallTestData currentTestData =
+        generateNewSmallTestData(m_TestData, 0, mpiRank, mpiSize);
+
+    std::string mpiRankString = std::to_string(mpiRank);
+    std::string s3_Single = std::string("s3_Single_") + mpiRankString;
+    std::string i8_Single = std::string("i8_Single_") + mpiRankString;
+    std::string i16_Single = std::string("i16_Single_") + mpiRankString;
+    std::string i32_Single = std::string("i32_Single_") + mpiRankString;
+    std::string i64_Single = std::string("i64_Single_") + mpiRankString;
+    std::string u8_Single = std::string("u8_Single_") + mpiRankString;
+    std::string u16_Single = std::string("u16_Single_") + mpiRankString;
+    std::string u32_Single = std::string("u32_Single_") + mpiRankString;
+    std::string u64_Single = std::string("u64_Single_") + mpiRankString;
+    std::string float_Single = std::string("float_Single_") + mpiRankString;
+    std::string double_Single = std::string("double_Single_") + mpiRankString;
+
     // Define ADIOS global value
-    const std::vector<std::string> vString{"-1", "0", "+1"};
-    const std::vector<char> vChar = {0, 0 + 1, 0 + 2};
-    const std::vector<unsigned char> vUChar = {1, 1 + 1, 1 + 2};
-    const std::vector<short> vShort = {2, 2 + 1, 2 + 2};
-    const std::vector<unsigned short> vUShort = {3, 3 + 1, 3 + 2};
-    const std::vector<int> vInt = {4, 4 + 1, 4 + 2};
-    const std::vector<unsigned int> vUInt = {5, 5 + 1, 5 + 2};
-    const std::vector<long int> vLInt = {6, 6 + 1, 6 + 2};
-    const std::vector<unsigned long int> vULInt = {7, 7 + 1, 7 + 2};
-    const std::vector<long long int> vLLInt = {8, 8 + 1, 8 + 2};
-    const std::vector<unsigned long long int> vULLInt = {9, 9 + 1, 9 + 2};
-    const std::vector<float> vFloat = {10, 10 + 1, 10 + 2};
-    const std::vector<double> vDouble = {11, 11 + 1, 11 + 2};
-    const std::vector<long double> vLDouble = {12, 12 + 1, 12 + 2};
-
-    auto &attributeString =
-        io.DefineAttribute<std::string>("attributeString", vString.data(), 3);
-
-    auto &attributeChar =
-        io.DefineAttribute<char>("attributeChar", vChar.data(), 3);
-    auto &attributeUChar =
-        io.DefineAttribute<unsigned char>("attributeUChar", vUChar.data(), 3);
-    auto &attributeShort =
-        io.DefineAttribute<short>("attributeShort", vShort.data(), 3);
-    auto &attributeUShort = io.DefineAttribute<unsigned short>(
-        "attributeUShort", vUShort.data(), 3);
-    auto &attributeInt =
-        io.DefineAttribute<int>("attributeInt", vInt.data(), 3);
-    auto &attributeUInt =
-        io.DefineAttribute<unsigned int>("attributeUInt", vUInt.data(), 3);
-    auto &attributeLInt =
-        io.DefineAttribute<long int>("attributeLInt", vLInt.data(), 3);
-    auto &attributeULInt = io.DefineAttribute<unsigned long int>(
-        "attributeULInt", vULInt.data(), 3);
-    auto &attributeLLInt =
-        io.DefineAttribute<long long int>("attributeLLInt", vLLInt.data(), 3);
-    auto &attributeULLInt = io.DefineAttribute<unsigned long long int>(
-        "attributeULLInt", vULLInt.data(), 3);
-    auto &attributeFloat =
-        io.DefineAttribute<float>("attributeFloat", vFloat.data(), 3);
-    auto &attributeDouble =
-        io.DefineAttribute<double>("attributeDouble", vDouble.data(), 3);
-    auto &attributeLDouble =
-        io.DefineAttribute<long double>("attributeLDouble", vLDouble.data(), 3);
+    auto &attributeS3 = io.DefineAttribute<std::string>(
+        s3_Single, currentTestData.S3.data(), 3);
+    auto &attributeI8 = io.DefineAttribute<int8_t>(
+        i8_Single, currentTestData.I8.data(), numberOfElements);
+    auto &attributeI16 = io.DefineAttribute<int16_t>(
+        i16_Single, currentTestData.I16.data(), numberOfElements);
+    auto &attributeI32 = io.DefineAttribute<int32_t>(
+        i32_Single, currentTestData.I32.data(), numberOfElements);
+    auto &attributeI64 = io.DefineAttribute<int64_t>(
+        i64_Single, currentTestData.I64.data(), numberOfElements);
+
+    auto &attributeU8 = io.DefineAttribute<uint8_t>(
+        u8_Single, currentTestData.U8.data(), numberOfElements);
+    auto &attributeU16 = io.DefineAttribute<uint16_t>(
+        u16_Single, currentTestData.U16.data(), numberOfElements);
+    auto &attributeU32 = io.DefineAttribute<uint32_t>(
+        u32_Single, currentTestData.U32.data(), numberOfElements);
+    auto &attributeU64 = io.DefineAttribute<uint64_t>(
+        u64_Single, currentTestData.U64.data(), numberOfElements);
+
+    auto &attributeFloat = io.DefineAttribute<float>(
+        float_Single, currentTestData.R32.data(), numberOfElements);
+    auto &attributeDouble = io.DefineAttribute<double>(
+        double_Single, currentTestData.R64.data(), numberOfElements);
 
     // Verify the return type is as expected
-    ::testing::StaticAssertTypeEq<decltype(attributeString),
+    ::testing::StaticAssertTypeEq<decltype(attributeS3),
                                   adios2::Attribute<std::string> &>();
-    ::testing::StaticAssertTypeEq<decltype(attributeChar),
-                                  adios2::Attribute<char> &>();
-    ::testing::StaticAssertTypeEq<decltype(attributeUChar),
-                                  adios2::Attribute<unsigned char> &>();
-    ::testing::StaticAssertTypeEq<decltype(attributeShort),
-                                  adios2::Attribute<short> &>();
-    ::testing::StaticAssertTypeEq<decltype(attributeUShort),
-                                  adios2::Attribute<unsigned short> &>();
-    ::testing::StaticAssertTypeEq<decltype(attributeInt),
-                                  adios2::Attribute<int> &>();
-    ::testing::StaticAssertTypeEq<decltype(attributeUInt),
-                                  adios2::Attribute<unsigned int> &>();
-    ::testing::StaticAssertTypeEq<decltype(attributeLInt),
-                                  adios2::Attribute<long int> &>();
-    ::testing::StaticAssertTypeEq<decltype(attributeULInt),
-                                  adios2::Attribute<unsigned long int> &>();
-    ::testing::StaticAssertTypeEq<decltype(attributeLLInt),
-                                  adios2::Attribute<long long int> &>();
-    ::testing::StaticAssertTypeEq<
-        decltype(attributeULLInt),
-        adios2::Attribute<unsigned long long int> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeI8),
+                                  adios2::Attribute<int8_t> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeI16),
+                                  adios2::Attribute<int16_t> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeI32),
+                                  adios2::Attribute<int32_t> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeI64),
+                                  adios2::Attribute<int64_t> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeU8),
+                                  adios2::Attribute<uint8_t> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeU16),
+                                  adios2::Attribute<uint16_t> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeU32),
+                                  adios2::Attribute<uint32_t> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeU64),
+                                  adios2::Attribute<uint64_t> &>();
     ::testing::StaticAssertTypeEq<decltype(attributeFloat),
                                   adios2::Attribute<float> &>();
     ::testing::StaticAssertTypeEq<decltype(attributeDouble),
                                   adios2::Attribute<double> &>();
-    ::testing::StaticAssertTypeEq<decltype(attributeLDouble),
-                                  adios2::Attribute<long double> &>();
-
-    // Verify the dimensions, name, and type are correct
-    ASSERT_EQ(attributeString.m_DataArray.empty(), false);
-    EXPECT_EQ(attributeString.m_DataArray[0], "-1");
-    EXPECT_EQ(attributeString.m_DataArray[1], "0");
-    EXPECT_EQ(attributeString.m_DataArray[2], "+1");
-    EXPECT_EQ(attributeString.m_Name, "attributeString");
-    ASSERT_EQ(attributeString.m_DataSingleValue.empty(), true);
-    EXPECT_EQ(attributeString.m_Elements, 3);
-    EXPECT_EQ(attributeString.m_Type, "string");
-
-    ASSERT_EQ(attributeChar.m_DataArray.empty(), false);
-    EXPECT_EQ(attributeChar.m_DataArray[0], 0);
-    EXPECT_EQ(attributeChar.m_DataArray[1], 0 + 1);
-    EXPECT_EQ(attributeChar.m_DataArray[2], 0 + 2);
-    EXPECT_EQ(attributeChar.m_Name, "attributeChar");
-    EXPECT_EQ(attributeChar.m_Elements, 3);
-    EXPECT_EQ(attributeChar.m_Type, "char");
-
-    ASSERT_EQ(attributeUChar.m_DataArray.empty(), false);
-    EXPECT_EQ(attributeUChar.m_DataArray[0], 1);
-    EXPECT_EQ(attributeUChar.m_DataArray[1], 1 + 1);
-    EXPECT_EQ(attributeUChar.m_DataArray[2], 1 + 2);
-    EXPECT_EQ(attributeUChar.m_Name, "attributeUChar");
-    EXPECT_EQ(attributeUChar.m_Elements, 3);
-    EXPECT_EQ(attributeUChar.m_Type, "unsigned char");
-
-    ASSERT_EQ(attributeShort.m_DataArray.empty(), false);
-    EXPECT_EQ(attributeShort.m_DataArray[0], 2);
-    EXPECT_EQ(attributeShort.m_DataArray[1], 2 + 1);
-    EXPECT_EQ(attributeShort.m_DataArray[2], 2 + 2);
-    EXPECT_EQ(attributeShort.m_Name, "attributeShort");
-    EXPECT_EQ(attributeShort.m_Elements, 3);
-    EXPECT_EQ(attributeShort.m_Type, "short");
-
-    ASSERT_EQ(attributeUShort.m_DataArray.empty(), false);
-    EXPECT_EQ(attributeUShort.m_DataArray[0], 3);
-    EXPECT_EQ(attributeUShort.m_DataArray[1], 3 + 1);
-    EXPECT_EQ(attributeUShort.m_DataArray[2], 3 + 2);
-    EXPECT_EQ(attributeUShort.m_Name, "attributeUShort");
-    EXPECT_EQ(attributeUShort.m_Elements, 3);
-    EXPECT_EQ(attributeUShort.m_Type, "unsigned short");
-
-    ASSERT_EQ(attributeInt.m_DataArray.empty(), false);
-    EXPECT_EQ(attributeInt.m_DataArray[0], 4);
-    EXPECT_EQ(attributeInt.m_DataArray[1], 4 + 1);
-    EXPECT_EQ(attributeInt.m_DataArray[2], 4 + 2);
-    EXPECT_EQ(attributeInt.m_Name, "attributeInt");
-    EXPECT_EQ(attributeInt.m_Elements, 3);
-    EXPECT_EQ(attributeInt.m_Type, "int");
-
-    ASSERT_EQ(attributeUInt.m_DataArray.empty(), false);
-    EXPECT_EQ(attributeUInt.m_DataArray[0], 5);
-    EXPECT_EQ(attributeUInt.m_DataArray[1], 5 + 1);
-    EXPECT_EQ(attributeUInt.m_DataArray[2], 5 + 2);
-    EXPECT_EQ(attributeUInt.m_Name, "attributeUInt");
-    EXPECT_EQ(attributeUInt.m_Elements, 3);
-    EXPECT_EQ(attributeUInt.m_Type, "unsigned int");
-
-    ASSERT_EQ(attributeLInt.m_DataArray.empty(), false);
-    EXPECT_EQ(attributeLInt.m_DataArray[0], 6);
-    EXPECT_EQ(attributeLInt.m_DataArray[1], 6 + 1);
-    EXPECT_EQ(attributeLInt.m_DataArray[2], 6 + 2);
-    EXPECT_EQ(attributeLInt.m_Name, "attributeLInt");
-    EXPECT_EQ(attributeLInt.m_Elements, 3);
-    EXPECT_EQ(attributeLInt.m_Type, "long int");
-
-    ASSERT_EQ(attributeULInt.m_DataArray.empty(), false);
-    EXPECT_EQ(attributeULInt.m_DataArray[0], 7);
-    EXPECT_EQ(attributeULInt.m_DataArray[1], 7 + 1);
-    EXPECT_EQ(attributeULInt.m_DataArray[2], 7 + 2);
-    EXPECT_EQ(attributeULInt.m_Name, "attributeULInt");
-    EXPECT_EQ(attributeULInt.m_Elements, 3);
-    EXPECT_EQ(attributeULInt.m_Type, "unsigned long int");
-
-    ASSERT_EQ(attributeLLInt.m_DataArray.empty(), false);
-    EXPECT_EQ(attributeLLInt.m_DataArray[0], 8);
-    EXPECT_EQ(attributeLLInt.m_DataArray[1], 8 + 1);
-    EXPECT_EQ(attributeLLInt.m_DataArray[2], 8 + 2);
-    EXPECT_EQ(attributeLLInt.m_Name, "attributeLLInt");
-    EXPECT_EQ(attributeLLInt.m_Elements, 3);
-    EXPECT_EQ(attributeLLInt.m_Type, "long long int");
-
-    ASSERT_EQ(attributeULLInt.m_DataArray.empty(), false);
-    EXPECT_EQ(attributeULLInt.m_DataArray[0], 9);
-    EXPECT_EQ(attributeULLInt.m_DataArray[1], 9 + 1);
-    EXPECT_EQ(attributeULLInt.m_DataArray[2], 9 + 2);
-    EXPECT_EQ(attributeULLInt.m_Name, "attributeULLInt");
-    EXPECT_EQ(attributeULLInt.m_Elements, 3);
-    EXPECT_EQ(attributeULLInt.m_Type, "unsigned long long int");
 
+    // Verify the members are correct
+    ASSERT_EQ(attributeS3.m_IsSingleValue, false);
+    ASSERT_EQ(attributeS3.m_DataArray.empty(), false);
+    EXPECT_EQ(attributeS3.m_Name, s3_Single);
+    EXPECT_EQ(attributeS3.m_Elements, 3);
+    EXPECT_EQ(attributeS3.m_Type, "string");
+
+    ASSERT_EQ(attributeI8.m_IsSingleValue, false);
+    ASSERT_EQ(attributeI8.m_DataArray.empty(), false);
+    EXPECT_EQ(attributeI8.m_Name, i8_Single);
+    EXPECT_EQ(attributeI8.m_Elements, numberOfElements);
+    EXPECT_EQ(attributeI8.m_Type, "signed char");
+
+    ASSERT_EQ(attributeI16.m_IsSingleValue, false);
+    ASSERT_EQ(attributeI16.m_DataArray.empty(), false);
+    EXPECT_EQ(attributeI16.m_Name, i16_Single);
+    EXPECT_EQ(attributeI16.m_Elements, numberOfElements);
+    EXPECT_EQ(attributeI16.m_Type, "short");
+
+    ASSERT_EQ(attributeI32.m_IsSingleValue, false);
+    ASSERT_EQ(attributeI32.m_DataArray.empty(), false);
+    EXPECT_EQ(attributeI32.m_Name, i32_Single);
+    EXPECT_EQ(attributeI32.m_Elements, numberOfElements);
+    EXPECT_EQ(attributeI32.m_Type, "int");
+
+    ASSERT_EQ(attributeI64.m_IsSingleValue, false);
+    ASSERT_EQ(attributeI64.m_DataArray.empty(), false);
+    EXPECT_EQ(attributeI64.m_Name, i64_Single);
+    EXPECT_EQ(attributeI64.m_Elements, numberOfElements);
+    EXPECT_EQ(attributeI64.m_Type, "long int");
+
+    ASSERT_EQ(attributeU8.m_IsSingleValue, false);
+    ASSERT_EQ(attributeU8.m_DataArray.empty(), false);
+    EXPECT_EQ(attributeU8.m_Name, u8_Single);
+    EXPECT_EQ(attributeU8.m_Elements, numberOfElements);
+    EXPECT_EQ(attributeU8.m_Type, "unsigned char");
+
+    ASSERT_EQ(attributeU16.m_IsSingleValue, false);
+    ASSERT_EQ(attributeU16.m_DataArray.empty(), false);
+    EXPECT_EQ(attributeU16.m_Name, u16_Single);
+    EXPECT_EQ(attributeU16.m_Elements, numberOfElements);
+    EXPECT_EQ(attributeU16.m_Type, "unsigned short");
+
+    ASSERT_EQ(attributeU32.m_IsSingleValue, false);
+    ASSERT_EQ(attributeU32.m_DataArray.empty(), false);
+    EXPECT_EQ(attributeU32.m_Name, u32_Single);
+    EXPECT_EQ(attributeU32.m_Elements, numberOfElements);
+    EXPECT_EQ(attributeU32.m_Type, "unsigned int");
+
+    ASSERT_EQ(attributeU64.m_IsSingleValue, false);
+    ASSERT_EQ(attributeU64.m_DataArray.empty(), false);
+    EXPECT_EQ(attributeU64.m_Name, u64_Single);
+    EXPECT_EQ(attributeU64.m_Elements, numberOfElements);
+    EXPECT_EQ(attributeU64.m_Type, "unsigned long int");
+
+    ASSERT_EQ(attributeFloat.m_IsSingleValue, false);
     ASSERT_EQ(attributeFloat.m_DataArray.empty(), false);
-    EXPECT_EQ(attributeFloat.m_DataArray[0], 10);
-    EXPECT_EQ(attributeFloat.m_DataArray[1], 10 + 1);
-    EXPECT_EQ(attributeFloat.m_DataArray[2], 10 + 2);
-    EXPECT_EQ(attributeFloat.m_Name, "attributeFloat");
-    EXPECT_EQ(attributeFloat.m_Elements, 3);
+    EXPECT_EQ(attributeFloat.m_Name, float_Single);
+    EXPECT_EQ(attributeFloat.m_Elements, numberOfElements);
     EXPECT_EQ(attributeFloat.m_Type, "float");
 
+    ASSERT_EQ(attributeDouble.m_IsSingleValue, false);
     ASSERT_EQ(attributeDouble.m_DataArray.empty(), false);
-    EXPECT_EQ(attributeDouble.m_DataArray[0], 11);
-    EXPECT_EQ(attributeDouble.m_DataArray[1], 11 + 1);
-    EXPECT_EQ(attributeDouble.m_DataArray[2], 11 + 2);
-    EXPECT_EQ(attributeDouble.m_Name, "attributeDouble");
-    EXPECT_EQ(attributeDouble.m_Elements, 3);
+    EXPECT_EQ(attributeDouble.m_Name, double_Single);
+    EXPECT_EQ(attributeDouble.m_Elements, numberOfElements);
     EXPECT_EQ(attributeDouble.m_Type, "double");
 
-    ASSERT_EQ(attributeLDouble.m_DataArray.empty(), false);
-    EXPECT_EQ(attributeLDouble.m_DataArray[0], 12);
-    EXPECT_EQ(attributeLDouble.m_DataArray[1], 12 + 1);
-    EXPECT_EQ(attributeLDouble.m_DataArray[2], 12 + 2);
-    EXPECT_EQ(attributeLDouble.m_Name, "attributeLDouble");
-    EXPECT_EQ(attributeLDouble.m_Elements, 3);
-    EXPECT_EQ(attributeLDouble.m_Type, "long double");
+    // Verify data
+    for (size_t index = 0; index < numberOfElements; index++)
+    {
+        EXPECT_EQ(attributeI8.m_DataArray[index], currentTestData.I8.at(index));
+        EXPECT_EQ(attributeI16.m_DataArray[index],
+                  currentTestData.I16.at(index));
+        EXPECT_EQ(attributeI32.m_DataArray[index],
+                  currentTestData.I32.at(index));
+        EXPECT_EQ(attributeU8.m_DataArray[index], currentTestData.U8.at(index));
+        EXPECT_EQ(attributeU16.m_DataArray[index],
+                  currentTestData.U16.at(index));
+        EXPECT_EQ(attributeU32.m_DataArray[index],
+                  currentTestData.U32.at(index));
+        EXPECT_EQ(attributeFloat.m_DataArray[index],
+                  currentTestData.R32.at(index));
+        EXPECT_EQ(attributeDouble.m_DataArray[index],
+                  currentTestData.R64.at(index));
+    }
 }
 
 TEST_F(ADIOSDefineAttributeTest, GetAttribute)
 {
-    // Define ADIOS global value
-    const std::vector<std::string> vString{"-1", "0", "+1"};
-    const std::vector<char> vChar = {0, 0 + 1, 0 + 2};
-    const std::vector<unsigned char> vUChar = {1, 1 + 1, 1 + 2};
-    const std::vector<short> vShort = {2, 2 + 1, 2 + 2};
-    const std::vector<unsigned short> vUShort = {3, 3 + 1, 3 + 2};
-    const std::vector<int> vInt = {4, 4 + 1, 4 + 2};
-    const std::vector<unsigned int> vUInt = {5, 5 + 1, 5 + 2};
-    const std::vector<long int> vLInt = {6, 6 + 1, 6 + 2};
-    const std::vector<unsigned long int> vULInt = {7, 7 + 1, 7 + 2};
-    const std::vector<long long int> vLLInt = {8, 8 + 1, 8 + 2};
-    const std::vector<unsigned long long int> vULLInt = {9, 9 + 1, 9 + 2};
-    const std::vector<float> vFloat = {10, 10 + 1, 10 + 2};
-    const std::vector<double> vDouble = {11, 11 + 1, 11 + 2};
-    const std::vector<long double> vLDouble = {12, 12 + 1, 12 + 2};
+    int mpiRank = 0, mpiSize = 1;
+    size_t numberOfElements = 10;
+#ifdef ADIOS2_HAVE_MPI
+    MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
+    MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
+#endif
 
+    // Define unique data for each process
+    SmallTestData currentTestData =
+        generateNewSmallTestData(m_TestData, 0, mpiRank, mpiSize);
+
+    std::string mpiRankString = std::to_string(mpiRank);
+    std::string s3_Single = std::string("s3_Single_") + mpiRankString;
+    std::string i8_Single = std::string("i8_Single_") + mpiRankString;
+    std::string i16_Single = std::string("i16_Single_") + mpiRankString;
+    std::string i32_Single = std::string("i32_Single_") + mpiRankString;
+    std::string i64_Single = std::string("i64_Single_") + mpiRankString;
+    std::string u8_Single = std::string("u8_Single_") + mpiRankString;
+    std::string u16_Single = std::string("u16_Single_") + mpiRankString;
+    std::string u32_Single = std::string("u32_Single_") + mpiRankString;
+    std::string u64_Single = std::string("u64_Single_") + mpiRankString;
+    std::string float_Single = std::string("float_Single_") + mpiRankString;
+    std::string double_Single = std::string("double_Single_") + mpiRankString;
+
+    // Define ADIOS global value
     {
-        io.DefineAttribute<std::string>("attributeString", vString.data(), 3);
-        io.DefineAttribute<char>("attributeChar", vChar.data(), 3);
-        io.DefineAttribute<unsigned char>("attributeUChar", vUChar.data(), 3);
-        io.DefineAttribute<short>("attributeShort", vShort.data(), 3);
-        io.DefineAttribute<unsigned short>("attributeUShort", vUShort.data(),
-                                           3);
-        io.DefineAttribute<int>("attributeInt", vInt.data(), 3);
-        io.DefineAttribute<unsigned int>("attributeUInt", vUInt.data(), 3);
-        io.DefineAttribute<long int>("attributeLInt", vLInt.data(), 3);
-        io.DefineAttribute<unsigned long int>("attributeULInt", vULInt.data(),
-                                              3);
-        io.DefineAttribute<long long int>("attributeLLInt", vLLInt.data(), 3);
-        io.DefineAttribute<unsigned long long int>("attributeULLInt",
-                                                   vULLInt.data(), 3);
-        io.DefineAttribute<float>("attributeFloat", vFloat.data(), 3);
-        io.DefineAttribute<double>("attributeDouble", vDouble.data(), 3);
-        io.DefineAttribute<long double>("attributeLDouble", vLDouble.data(), 3);
+        io.DefineAttribute<std::string>(s3_Single, currentTestData.S3.data(),
+                                        3);
+        io.DefineAttribute<int8_t>(i8_Single, currentTestData.I8.data(),
+                                   numberOfElements);
+        io.DefineAttribute<int16_t>(i16_Single, currentTestData.I16.data(),
+                                    numberOfElements);
+        io.DefineAttribute<int32_t>(i32_Single, currentTestData.I32.data(),
+                                    numberOfElements);
+        io.DefineAttribute<int64_t>(i64_Single, currentTestData.I64.data(),
+                                    numberOfElements);
+        io.DefineAttribute<uint8_t>(u8_Single, currentTestData.U8.data(),
+                                    numberOfElements);
+        io.DefineAttribute<uint16_t>(u16_Single, currentTestData.U16.data(),
+                                     numberOfElements);
+        io.DefineAttribute<uint32_t>(u32_Single, currentTestData.U32.data(),
+                                     numberOfElements);
+        io.DefineAttribute<uint64_t>(u64_Single, currentTestData.U64.data(),
+                                     numberOfElements);
+        io.DefineAttribute<float>(float_Single, currentTestData.R32.data(),
+                                  numberOfElements);
+        io.DefineAttribute<double>(double_Single, currentTestData.R64.data(),
+                                   numberOfElements);
     }
 
-    auto &attributeString = io.GetAttribute<std::string>("attributeString");
-    auto &attributeChar = io.GetAttribute<char>("attributeChar");
-    auto &attributeUChar = io.GetAttribute<unsigned char>("attributeUChar");
-    auto &attributeShort = io.GetAttribute<short>("attributeShort");
-    auto &attributeUShort = io.GetAttribute<unsigned short>("attributeUShort");
-    auto &attributeInt = io.GetAttribute<int>("attributeInt");
-    auto &attributeUInt = io.GetAttribute<unsigned int>("attributeUInt");
-    auto &attributeLInt = io.GetAttribute<long int>("attributeLInt");
-    auto &attributeULInt = io.GetAttribute<unsigned long int>("attributeULInt");
-    auto &attributeLLInt = io.GetAttribute<long long int>("attributeLLInt");
-    auto &attributeULLInt =
-        io.GetAttribute<unsigned long long int>("attributeULLInt");
-    auto &attributeFloat = io.GetAttribute<float>("attributeFloat");
-    auto &attributeDouble = io.GetAttribute<double>("attributeDouble");
-    auto &attributeLDouble = io.GetAttribute<long double>("attributeLDouble");
+    auto &attributeS3 = io.GetAttribute<std::string>(s3_Single);
+    auto &attributeI8 = io.GetAttribute<int8_t>(i8_Single);
+    auto &attributeI16 = io.GetAttribute<int16_t>(i16_Single);
+    auto &attributeI32 = io.GetAttribute<int32_t>(i32_Single);
+    auto &attributeI64 = io.GetAttribute<int64_t>(i64_Single);
+    auto &attributeU8 = io.GetAttribute<uint8_t>(i8_Single);
+    auto &attributeU16 = io.GetAttribute<uint16_t>(i16_Single);
+    auto &attributeU32 = io.GetAttribute<uint32_t>(i32_Single);
+    auto &attributeU64 = io.GetAttribute<uint64_t>(i64_Single);
+    auto &attributeFloat = io.GetAttribute<float>(float_Single);
+    auto &attributeDouble = io.GetAttribute<double>(double_Single);
 
     // Verify the return type is as expected
-    ::testing::StaticAssertTypeEq<decltype(attributeString),
+    ::testing::StaticAssertTypeEq<decltype(attributeS3),
                                   adios2::Attribute<std::string> &>();
-    ::testing::StaticAssertTypeEq<decltype(attributeChar),
-                                  adios2::Attribute<char> &>();
-    ::testing::StaticAssertTypeEq<decltype(attributeUChar),
-                                  adios2::Attribute<unsigned char> &>();
-    ::testing::StaticAssertTypeEq<decltype(attributeShort),
-                                  adios2::Attribute<short> &>();
-    ::testing::StaticAssertTypeEq<decltype(attributeUShort),
-                                  adios2::Attribute<unsigned short> &>();
-    ::testing::StaticAssertTypeEq<decltype(attributeInt),
-                                  adios2::Attribute<int> &>();
-    ::testing::StaticAssertTypeEq<decltype(attributeUInt),
-                                  adios2::Attribute<unsigned int> &>();
-    ::testing::StaticAssertTypeEq<decltype(attributeLInt),
-                                  adios2::Attribute<long int> &>();
-    ::testing::StaticAssertTypeEq<decltype(attributeULInt),
-                                  adios2::Attribute<unsigned long int> &>();
-    ::testing::StaticAssertTypeEq<decltype(attributeLLInt),
-                                  adios2::Attribute<long long int> &>();
-    ::testing::StaticAssertTypeEq<
-        decltype(attributeULLInt),
-        adios2::Attribute<unsigned long long int> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeI8),
+                                  adios2::Attribute<int8_t> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeI16),
+                                  adios2::Attribute<int16_t> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeI32),
+                                  adios2::Attribute<int32_t> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeI64),
+                                  adios2::Attribute<int64_t> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeU8),
+                                  adios2::Attribute<uint8_t> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeU16),
+                                  adios2::Attribute<uint16_t> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeU32),
+                                  adios2::Attribute<uint32_t> &>();
+    ::testing::StaticAssertTypeEq<decltype(attributeU64),
+                                  adios2::Attribute<uint64_t> &>();
     ::testing::StaticAssertTypeEq<decltype(attributeFloat),
                                   adios2::Attribute<float> &>();
     ::testing::StaticAssertTypeEq<decltype(attributeDouble),
                                   adios2::Attribute<double> &>();
-    ::testing::StaticAssertTypeEq<decltype(attributeLDouble),
-                                  adios2::Attribute<long double> &>();
-
-    // Verify the dimensions, name, and type are correct
-    ASSERT_EQ(attributeString.m_DataArray.empty(), false);
-    EXPECT_EQ(attributeString.m_DataArray[0], "-1");
-    EXPECT_EQ(attributeString.m_DataArray[1], "0");
-    EXPECT_EQ(attributeString.m_DataArray[2], "+1");
-    EXPECT_EQ(attributeString.m_Name, "attributeString");
-    ASSERT_EQ(attributeString.m_DataSingleValue.empty(), true);
-    EXPECT_EQ(attributeString.m_Elements, 3);
-    EXPECT_EQ(attributeString.m_Type, "string");
-
-    ASSERT_EQ(attributeChar.m_DataArray.empty(), false);
-    EXPECT_EQ(attributeChar.m_DataArray[0], 0);
-    EXPECT_EQ(attributeChar.m_DataArray[1], 0 + 1);
-    EXPECT_EQ(attributeChar.m_DataArray[2], 0 + 2);
-    EXPECT_EQ(attributeChar.m_Name, "attributeChar");
-    EXPECT_EQ(attributeChar.m_Elements, 3);
-    EXPECT_EQ(attributeChar.m_Type, "char");
-
-    ASSERT_EQ(attributeUChar.m_DataArray.empty(), false);
-    EXPECT_EQ(attributeUChar.m_DataArray[0], 1);
-    EXPECT_EQ(attributeUChar.m_DataArray[1], 1 + 1);
-    EXPECT_EQ(attributeUChar.m_DataArray[2], 1 + 2);
-    EXPECT_EQ(attributeUChar.m_Name, "attributeUChar");
-    EXPECT_EQ(attributeUChar.m_Elements, 3);
-    EXPECT_EQ(attributeUChar.m_Type, "unsigned char");
-
-    ASSERT_EQ(attributeShort.m_DataArray.empty(), false);
-    EXPECT_EQ(attributeShort.m_DataArray[0], 2);
-    EXPECT_EQ(attributeShort.m_DataArray[1], 2 + 1);
-    EXPECT_EQ(attributeShort.m_DataArray[2], 2 + 2);
-    EXPECT_EQ(attributeShort.m_Name, "attributeShort");
-    EXPECT_EQ(attributeShort.m_Elements, 3);
-    EXPECT_EQ(attributeShort.m_Type, "short");
-
-    ASSERT_EQ(attributeUShort.m_DataArray.empty(), false);
-    EXPECT_EQ(attributeUShort.m_DataArray[0], 3);
-    EXPECT_EQ(attributeUShort.m_DataArray[1], 3 + 1);
-    EXPECT_EQ(attributeUShort.m_DataArray[2], 3 + 2);
-    EXPECT_EQ(attributeUShort.m_Name, "attributeUShort");
-    EXPECT_EQ(attributeUShort.m_Elements, 3);
-    EXPECT_EQ(attributeUShort.m_Type, "unsigned short");
-
-    ASSERT_EQ(attributeInt.m_DataArray.empty(), false);
-    EXPECT_EQ(attributeInt.m_DataArray[0], 4);
-    EXPECT_EQ(attributeInt.m_DataArray[1], 4 + 1);
-    EXPECT_EQ(attributeInt.m_DataArray[2], 4 + 2);
-    EXPECT_EQ(attributeInt.m_Name, "attributeInt");
-    EXPECT_EQ(attributeInt.m_Elements, 3);
-    EXPECT_EQ(attributeInt.m_Type, "int");
-
-    ASSERT_EQ(attributeUInt.m_DataArray.empty(), false);
-    EXPECT_EQ(attributeUInt.m_DataArray[0], 5);
-    EXPECT_EQ(attributeUInt.m_DataArray[1], 5 + 1);
-    EXPECT_EQ(attributeUInt.m_DataArray[2], 5 + 2);
-    EXPECT_EQ(attributeUInt.m_Name, "attributeUInt");
-    EXPECT_EQ(attributeUInt.m_Elements, 3);
-    EXPECT_EQ(attributeUInt.m_Type, "unsigned int");
-
-    ASSERT_EQ(attributeLInt.m_DataArray.empty(), false);
-    EXPECT_EQ(attributeLInt.m_DataArray[0], 6);
-    EXPECT_EQ(attributeLInt.m_DataArray[1], 6 + 1);
-    EXPECT_EQ(attributeLInt.m_DataArray[2], 6 + 2);
-    EXPECT_EQ(attributeLInt.m_Name, "attributeLInt");
-    EXPECT_EQ(attributeLInt.m_Elements, 3);
-    EXPECT_EQ(attributeLInt.m_Type, "long int");
-
-    ASSERT_EQ(attributeULInt.m_DataArray.empty(), false);
-    EXPECT_EQ(attributeULInt.m_DataArray[0], 7);
-    EXPECT_EQ(attributeULInt.m_DataArray[1], 7 + 1);
-    EXPECT_EQ(attributeULInt.m_DataArray[2], 7 + 2);
-    EXPECT_EQ(attributeULInt.m_Name, "attributeULInt");
-    EXPECT_EQ(attributeULInt.m_Elements, 3);
-    EXPECT_EQ(attributeULInt.m_Type, "unsigned long int");
-
-    ASSERT_EQ(attributeLLInt.m_DataArray.empty(), false);
-    EXPECT_EQ(attributeLLInt.m_DataArray[0], 8);
-    EXPECT_EQ(attributeLLInt.m_DataArray[1], 8 + 1);
-    EXPECT_EQ(attributeLLInt.m_DataArray[2], 8 + 2);
-    EXPECT_EQ(attributeLLInt.m_Name, "attributeLLInt");
-    EXPECT_EQ(attributeLLInt.m_Elements, 3);
-    EXPECT_EQ(attributeLLInt.m_Type, "long long int");
-
-    ASSERT_EQ(attributeULLInt.m_DataArray.empty(), false);
-    EXPECT_EQ(attributeULLInt.m_DataArray[0], 9);
-    EXPECT_EQ(attributeULLInt.m_DataArray[1], 9 + 1);
-    EXPECT_EQ(attributeULLInt.m_DataArray[2], 9 + 2);
-    EXPECT_EQ(attributeULLInt.m_Name, "attributeULLInt");
-    EXPECT_EQ(attributeULLInt.m_Elements, 3);
-    EXPECT_EQ(attributeULLInt.m_Type, "unsigned long long int");
 
+    // Verify the members are correct
+    ASSERT_EQ(attributeS3.m_IsSingleValue, false);
+    ASSERT_EQ(attributeS3.m_DataArray.empty(), false);
+    EXPECT_EQ(attributeS3.m_Name, s3_Single);
+    EXPECT_EQ(attributeS3.m_Elements, 3);
+    EXPECT_EQ(attributeS3.m_Type, "string");
+
+    ASSERT_EQ(attributeI8.m_IsSingleValue, false);
+    ASSERT_EQ(attributeI8.m_DataArray.empty(), false);
+    EXPECT_EQ(attributeI8.m_Name, i8_Single);
+    EXPECT_EQ(attributeI8.m_Elements, numberOfElements);
+    EXPECT_EQ(attributeI8.m_Type, "signed char");
+
+    ASSERT_EQ(attributeI16.m_IsSingleValue, false);
+    ASSERT_EQ(attributeI16.m_DataArray.empty(), false);
+    EXPECT_EQ(attributeI16.m_Name, i16_Single);
+    EXPECT_EQ(attributeI16.m_Elements, numberOfElements);
+    EXPECT_EQ(attributeI16.m_Type, "short");
+
+    ASSERT_EQ(attributeI32.m_IsSingleValue, false);
+    ASSERT_EQ(attributeI32.m_DataArray.empty(), false);
+    EXPECT_EQ(attributeI32.m_Name, i32_Single);
+    EXPECT_EQ(attributeI32.m_Elements, numberOfElements);
+    EXPECT_EQ(attributeI32.m_Type, "int");
+
+    ASSERT_EQ(attributeI64.m_IsSingleValue, false);
+    ASSERT_EQ(attributeI64.m_DataArray.empty(), false);
+    EXPECT_EQ(attributeI64.m_Name, i64_Single);
+    EXPECT_EQ(attributeI64.m_Elements, numberOfElements);
+    EXPECT_EQ(attributeI64.m_Type, "long int");
+
+    ASSERT_EQ(attributeU8.m_IsSingleValue, false);
+    ASSERT_EQ(attributeU8.m_DataArray.empty(), false);
+    EXPECT_EQ(attributeU8.m_Name, u8_Single);
+    EXPECT_EQ(attributeU8.m_Elements, numberOfElements);
+    EXPECT_EQ(attributeU8.m_Type, "unsigned char");
+
+    ASSERT_EQ(attributeU16.m_IsSingleValue, false);
+    ASSERT_EQ(attributeU16.m_DataArray.empty(), false);
+    EXPECT_EQ(attributeU16.m_Name, u16_Single);
+    EXPECT_EQ(attributeU16.m_Elements, numberOfElements);
+    EXPECT_EQ(attributeU16.m_Type, "unsigned short");
+
+    ASSERT_EQ(attributeU32.m_IsSingleValue, false);
+    ASSERT_EQ(attributeU32.m_DataArray.empty(), false);
+    EXPECT_EQ(attributeU32.m_Name, u32_Single);
+    EXPECT_EQ(attributeU32.m_Elements, numberOfElements);
+    EXPECT_EQ(attributeU32.m_Type, "unsigned int");
+
+    ASSERT_EQ(attributeU64.m_IsSingleValue, false);
+    ASSERT_EQ(attributeU64.m_DataArray.empty(), false);
+    EXPECT_EQ(attributeU64.m_Name, u64_Single);
+    EXPECT_EQ(attributeU64.m_Elements, numberOfElements);
+    EXPECT_EQ(attributeU64.m_Type, "unsigned long int");
+
+    ASSERT_EQ(attributeFloat.m_IsSingleValue, false);
     ASSERT_EQ(attributeFloat.m_DataArray.empty(), false);
-    EXPECT_EQ(attributeFloat.m_DataArray[0], 10);
-    EXPECT_EQ(attributeFloat.m_DataArray[1], 10 + 1);
-    EXPECT_EQ(attributeFloat.m_DataArray[2], 10 + 2);
-    EXPECT_EQ(attributeFloat.m_Name, "attributeFloat");
-    EXPECT_EQ(attributeFloat.m_Elements, 3);
+    EXPECT_EQ(attributeFloat.m_Name, float_Single);
+    EXPECT_EQ(attributeFloat.m_Elements, numberOfElements);
     EXPECT_EQ(attributeFloat.m_Type, "float");
 
+    ASSERT_EQ(attributeDouble.m_IsSingleValue, false);
     ASSERT_EQ(attributeDouble.m_DataArray.empty(), false);
-    EXPECT_EQ(attributeDouble.m_DataArray[0], 11);
-    EXPECT_EQ(attributeDouble.m_DataArray[1], 11 + 1);
-    EXPECT_EQ(attributeDouble.m_DataArray[2], 11 + 2);
-    EXPECT_EQ(attributeDouble.m_Name, "attributeDouble");
-    EXPECT_EQ(attributeDouble.m_Elements, 3);
+    EXPECT_EQ(attributeDouble.m_Name, double_Single);
+    EXPECT_EQ(attributeDouble.m_Elements, numberOfElements);
     EXPECT_EQ(attributeDouble.m_Type, "double");
 
-    ASSERT_EQ(attributeLDouble.m_DataArray.empty(), false);
-    EXPECT_EQ(attributeLDouble.m_DataArray[0], 12);
-    EXPECT_EQ(attributeLDouble.m_DataArray[1], 12 + 1);
-    EXPECT_EQ(attributeLDouble.m_DataArray[2], 12 + 2);
-    EXPECT_EQ(attributeLDouble.m_Name, "attributeLDouble");
-    EXPECT_EQ(attributeLDouble.m_Elements, 3);
-    EXPECT_EQ(attributeLDouble.m_Type, "long double");
+    // Verify data
+    for (size_t index = 0; index < numberOfElements; index++)
+    {
+        EXPECT_EQ(attributeI8.m_DataArray[index], currentTestData.I8.at(index));
+        EXPECT_EQ(attributeI16.m_DataArray[index],
+                  currentTestData.I16.at(index));
+        EXPECT_EQ(attributeI32.m_DataArray[index],
+                  currentTestData.I32.at(index));
+        EXPECT_EQ(attributeU8.m_DataArray[index], currentTestData.U8.at(index));
+        EXPECT_EQ(attributeU16.m_DataArray[index],
+                  currentTestData.U16.at(index));
+        EXPECT_EQ(attributeU32.m_DataArray[index],
+                  currentTestData.U32.at(index));
+        EXPECT_EQ(attributeFloat.m_DataArray[index],
+                  currentTestData.R32.at(index));
+        EXPECT_EQ(attributeDouble.m_DataArray[index],
+                  currentTestData.R64.at(index));
+    }
 }
 
 int main(int argc, char **argv)
-- 
GitLab