/** * * \section COPYRIGHT * * Copyright 2013-2021 Software Radio Systems Limited * * By using this file, you agree to the terms and conditions set * forth in the LICENSE file which can be found at the top level of * the distribution. * */ #include "srsran/asn1/asn1_utils.h" #include "srsran/common/test_common.h" #include #include #include using namespace std; using namespace asn1; std::random_device rd; std::mt19937 g(rd()); srsran::log_sink_spy* test_spy = nullptr; int test_arrays() { /* Test Ext Array */ ext_array ext_ar; const int* old_ptr = ext_ar.data(); // Test Resize until goes out of small buffer for (uint32_t i = 0; i < ext_ar.small_buffer_size + 1; ++i) { TESTASSERT(ext_ar.is_in_small_buffer()); TESTASSERT(ext_ar.capacity() == ext_ar.small_buffer_size); TESTASSERT(ext_ar.size() == i); ext_ar.push_back(i); } TESTASSERT(not ext_ar.is_in_small_buffer()); TESTASSERT(ext_ar.size() == ext_ar.small_buffer_size + 1); TESTASSERT(old_ptr != ext_ar.data()); TESTASSERT(ext_ar.capacity() > ext_ar.small_buffer_size); // Test Copy { ext_array ext_ar2(ext_ar); TESTASSERT(ext_ar2 == ext_ar); TESTASSERT(not ext_ar.is_in_small_buffer()); } TESTASSERT(ext_ar.size() == 5); // Test Move { ext_array ext_ar2(std::move(ext_ar)); TESTASSERT(ext_ar.is_in_small_buffer()); TESTASSERT(ext_ar2.size() == 5); TESTASSERT(ext_ar2[2] == 2); } ext_ar = ext_array(5); TESTASSERT(not ext_ar.is_in_small_buffer()); TESTASSERT(ext_ar.size() == 5); ext_ar.resize(0); TESTASSERT(not ext_ar.is_in_small_buffer()); return 0; } int test_bit_ref() { uint8_t buf[1024]; // one bit at a time { uint32_t nof_bytes = 2; bit_ref bref(&buf[0], nof_bytes); bit_ref bref0 = bref; for (uint32_t i = 0; i < 8 * nof_bytes; ++i) { bref.pack(i, 1); } uint8_t a[] = {85, 85}; TESTASSERT(bref.distance(bref0) / 8 == (int)nof_bytes); TESTASSERT(memcmp(a, buf, nof_bytes) == 0); bit_ref bref2(&buf[0], nof_bytes); for (uint32_t i = 0; i < 8 * nof_bytes; ++i) { bool val; bref2.unpack(val, 1); TESTASSERT((i & 1) == val); } } // three bits at a time { uint32_t nof_bytes = 3; bit_ref bref(&buf[0], nof_bytes); bit_ref bref0 = bref; for (uint32_t i = 0; i < 8 * nof_bytes / 3; ++i) { bref.pack(i, 3); } uint8_t a[] = {5, 57, 119}; TESTASSERT(bref.distance(bref0) / 8 == (int)nof_bytes); TESTASSERT(memcmp(a, buf, nof_bytes) == 0); bit_ref bref2(&buf[0], nof_bytes); for (uint32_t i = 0; i < 8 * nof_bytes / 3; ++i) { uint32_t val; bref2.unpack(val, 3); TESTASSERT((i & 7) == val); } } // 16 bits at a time { uint32_t nof_bytes = 32, bitstride = 16; uint32_t start = 256, mask = (1u << bitstride) - 1u; bit_ref bref(&buf[0], nof_bytes); for (uint32_t i = 0; i < 8 * nof_bytes / bitstride; ++i) { bref.pack(i + start, bitstride); } uint8_t a[] = {1, 0, 1, 1, 1, 2, 1, 3, 1, 4}; TESTASSERT(bref.distance_bytes() == (int32_t)nof_bytes); TESTASSERT(memcmp(a, buf, sizeof(a)) == 0); bit_ref bref2(&buf[0], nof_bytes); for (uint32_t i = 0; i < 8 * nof_bytes / bitstride; ++i) { uint32_t val; bref2.unpack(val, bitstride); TESTASSERT(((i + start) & mask) == val); } } // pack bytes aligned { uint32_t nof_bytes = 512; uint32_t start = 1; bit_ref bref(&buf[0], sizeof(buf)); uint8_t buf2[1024]; for (uint32_t i = 0; i < sizeof(buf2); ++i) { buf2[i] = start + i; } TESTASSERT(bref.pack_bytes(buf2, nof_bytes) == SRSASN_SUCCESS); TESTASSERT(bref.distance_bytes() == (int)nof_bytes); TESTASSERT(memcmp(buf2, buf, bref.distance_bytes()) == 0); bit_ref bref2(&buf[0], sizeof(buf)); TESTASSERT(bref2.unpack_bytes(&buf2[0], nof_bytes) == SRSASN_SUCCESS); TESTASSERT(bref2.distance_bytes() == (int)nof_bytes); TESTASSERT(memcmp(buf2, buf, bref.distance_bytes()) == 0); } // pack bytes unaligned { uint32_t nof_bytes = 128; uint32_t start = 1; bit_ref bref(&buf[0], sizeof(buf)); uint8_t buf2[1024], buf3[1024]; for (uint32_t i = 0; i < sizeof(buf2); ++i) { buf2[i] = start + i; } bzero(buf3, sizeof(buf3)); // this unaligns TESTASSERT(bref.pack(0, 1) == SRSASN_SUCCESS); TESTASSERT(bref.pack_bytes(buf2, nof_bytes) == SRSASN_SUCCESS); TESTASSERT(bref.distance_bytes() == (int)nof_bytes + 1); uint8_t ar[] = {0, 129, 1, 130, 2, 131, 3, 132, 4, 133, 5}; TESTASSERT(memcmp(ar, buf, sizeof(ar)) == 0); bit_ref bref2(&buf[0], sizeof(buf)); uint32_t val; TESTASSERT(bref2.unpack(val, 1) == SRSASN_SUCCESS); TESTASSERT(val == 0); TESTASSERT(bref2.unpack_bytes(&buf3[0], nof_bytes) == SRSASN_SUCCESS); TESTASSERT(bref2.distance_bytes() == (int)nof_bytes + 1); TESTASSERT(bref2.distance_bytes() == bref.distance_bytes()); TESTASSERT(memcmp(buf2, buf3, nof_bytes) == 0); } // test advance bits { bit_ref bref(&buf[0], sizeof(buf)); TESTASSERT(bref.advance_bits(4) == SRSASN_SUCCESS); TESTASSERT(bref.distance() == 4); TESTASSERT(bref.advance_bits(4) == SRSASN_SUCCESS); TESTASSERT(bref.distance() == 8); TESTASSERT(bref.advance_bits(3) == SRSASN_SUCCESS); TESTASSERT(bref.distance() == 11); TESTASSERT(bref.advance_bits(200) == SRSASN_SUCCESS); TESTASSERT(bref.distance() == 211); TESTASSERT(bref.advance_bits(5) == SRSASN_SUCCESS); TESTASSERT(bref.distance() == 216); } return 0; } int test_oct_string() { uint8_t buf[1024]; bit_ref b(&buf[0], sizeof(buf)); cbit_ref b2(&buf[0], sizeof(buf)); bit_ref borig(b); std::string hexstr = "014477aaff"; fixed_octstring<5> statstr; dyn_octstring dynstr; statstr.from_string(hexstr); dynstr.from_string(hexstr); TESTASSERT(sizeof(statstr) == statstr.size()); TESTASSERT(statstr.size() == 5); TESTASSERT(dynstr.size() == 5); TESTASSERT(dynstr[0] == 1); TESTASSERT(statstr[4] == 255); TESTASSERT(statstr.to_string() == hexstr); TESTASSERT(statstr.to_string() == dynstr.to_string()); TESTASSERT(statstr.to_number() == dynstr.to_number()); // check endianess TESTASSERT(statstr.to_number() == 5443660543); TESTASSERT(dynstr.to_number() == 5443660543); dynstr.from_number(dynstr.to_number()); TESTASSERT(dynstr.to_number() == 5443660543); statstr.pack(b); TESTASSERT(memcmp(&buf[0], &statstr[0], statstr.size()) == 0); TESTASSERT(b.distance(borig) == (int)statstr.size() * 8); fixed_octstring<5> statstr2; b2 = cbit_ref(&buf[0], sizeof(buf)); statstr2.unpack(b2); TESTASSERT(statstr == statstr2); b = borig; dynstr.pack(b); TESTASSERT(buf[0] == dynstr.size()); // true for small strings TESTASSERT(memcmp(&buf[1], &dynstr[0], dynstr.size()) == 0); TESTASSERT(b.distance(borig) == (int)(dynstr.size() * 8 + 8)); dyn_octstring dynstr2; // unpacker allocates automatically b2 = cbit_ref(&buf[0], sizeof(buf)); dynstr2.unpack(b2); TESTASSERT(dynstr == dynstr2); // test copy ctor { fixed_octstring<5> statcopy(statstr); TESTASSERT(statcopy == statstr); } { dyn_octstring scopy(dynstr); TESTASSERT(scopy == dynstr); } b.pack(1, 1); TESTASSERT(b.distance(borig) == (int)(hexstr.size() * 8 / 2 + 9)); b.align_bytes_zero(); TESTASSERT(b.distance(borig) == (int)(hexstr.size() * 8 / 2 + 16)); return 0; } int test_bitstring() { fixed_bitstring<10> bstr1; bounded_bitstring<5, 15> bound_bstr1(10); dyn_bitstring dyn_bstr1(10); bstr1.set(7, true); bstr1.set(9, true); bound_bstr1.set(7, true); bound_bstr1.set(9, true); dyn_bstr1.set(7, true); dyn_bstr1.set(9, true); /* Test BitSet and BitGet and Length */ // fixed TESTASSERT(bstr1.length() == 10); TESTASSERT(bstr1.get(7)); TESTASSERT(bstr1.get(9)); TESTASSERT(not bstr1.get(8)); TESTASSERT(not bstr1.get(0)); // bounded TESTASSERT(bound_bstr1.length() == 10); TESTASSERT(bound_bstr1.get(7)); TESTASSERT(bound_bstr1.get(9)); TESTASSERT(not bound_bstr1.get(8)); TESTASSERT(not bound_bstr1.get(0)); // dyn TESTASSERT(dyn_bstr1.length() == 10); TESTASSERT(dyn_bstr1.get(7)); TESTASSERT(dyn_bstr1.get(9)); TESTASSERT(not dyn_bstr1.get(8)); TESTASSERT(not dyn_bstr1.get(0)); /* Test Copy, Dtor, and Equal Comparison */ { // fixed fixed_bitstring<10> bstr2; bstr2 = bstr1; TESTASSERT(bstr2 == bstr1); // bound bounded_bitstring<5, 15> bound_bstr2; bound_bstr2 = bound_bstr1; TESTASSERT(bound_bstr2 == bound_bstr1); // dyn dyn_bitstring dyn_bstr2(10); dyn_bstr2 = dyn_bstr1; TESTASSERT(dyn_bstr2 == dyn_bstr1); // dtors called } /* Test Number and String conversion */ // fixed TESTASSERT(bstr1.to_string() == "1010000000"); TESTASSERT(bstr1.to_number() == 640); bstr1.set(1, true); TESTASSERT(bstr1.to_string() == "1010000010"); TESTASSERT(bstr1.to_number() == 642); TESTASSERT(bstr1 == fixed_bitstring<10>().from_number(642)); // bounded TESTASSERT(bound_bstr1.to_string() == "1010000000"); TESTASSERT(bound_bstr1.to_number() == 640); bound_bstr1.set(1, true); TESTASSERT(bound_bstr1.to_string() == "1010000010"); TESTASSERT(bound_bstr1.to_number() == 642); TESTASSERT((bound_bstr1 == bounded_bitstring<5, 15>().from_number(642))); TESTASSERT((bound_bstr1 == bounded_bitstring<5, 15>().from_string("1010000010"))); // dyn TESTASSERT(dyn_bstr1.to_string() == "1010000000"); TESTASSERT(dyn_bstr1.to_number() == 640); dyn_bstr1.set(1, true); TESTASSERT(dyn_bstr1.to_string() == "1010000010"); TESTASSERT(dyn_bstr1.to_number() == 642); TESTASSERT(dyn_bstr1 == dyn_bitstring().from_number(642)); TESTASSERT(dyn_bstr1 == dyn_bitstring().from_string("1010000010")); // zero case TESTASSERT(bound_bstr1.from_number(0) == "00000"); /* Test Resize */ bound_bstr1.resize(11); TESTASSERT(not bound_bstr1.get(9)); // resets content TESTASSERT(bound_bstr1.length() == 11); bound_bstr1.set(9, true); dyn_bstr1.resize(11); TESTASSERT(not dyn_bstr1.get(9)); TESTASSERT(dyn_bstr1.length() == 11); dyn_bstr1.set(9, true); TESTASSERT(dyn_bstr1.get(9)); TESTASSERT(not dyn_bstr1.get(10)); /* Test Packing/Unpacking */ uint8_t buffer[1024]; bit_ref bref(&buffer[0], sizeof(buffer)); cbit_ref bref2(&buffer[0], sizeof(buffer)); // fixed TESTASSERT(bstr1.pack(bref) == SRSASN_SUCCESS); fixed_bitstring<10> bstr2; TESTASSERT(bstr2.length() == 10); TESTASSERT(bstr2.unpack(bref2) == SRSASN_SUCCESS); TESTASSERT(bstr2 == bstr1); TESTASSERT(bref.distance() == 10 and bref.distance() == bref2.distance()); // bounded bref = bit_ref(&buffer[0], sizeof(buffer)); bref2 = cbit_ref(&buffer[0], sizeof(buffer)); TESTASSERT(bound_bstr1.pack(bref) == SRSASN_SUCCESS); bounded_bitstring<5, 15> bound_bstr2(dyn_bstr1.length()); TESTASSERT(bound_bstr2.length() == 11); TESTASSERT(bound_bstr2.unpack(bref2) == SRSASN_SUCCESS); TESTASSERT(bound_bstr2 == bound_bstr1); TESTASSERT(bref.distance() == (11 + 4) and bref.distance() == bref2.distance()); // dyn bref = bit_ref(&buffer[0], sizeof(buffer)); bref2 = cbit_ref(&buffer[0], sizeof(buffer)); TESTASSERT(dyn_bstr1.pack(bref) == SRSASN_SUCCESS); dyn_bitstring dyn_bstr2(dyn_bstr1.length()); TESTASSERT(dyn_bstr2.length() == 11); TESTASSERT(dyn_bstr2.unpack(bref2) == SRSASN_SUCCESS); TESTASSERT(dyn_bstr2 == dyn_bstr1); // printf("%s==%s\n", dyn_bstr1.to_string().c_str(), dyn_bstr2.to_string().c_str()); // disable temporarily the prints to check failures // srsran::nullsink_log null_log("NULL"); // bit_ref bref3(&buffer[0], sizeof(buffer)); // TESTASSERT(dyn_bstr1.pack(bref3, false, 5, 10)==SRSASN_ERROR_ENCODE_FAIL); /* Test Pack/Unpack 2 */ buffer[0] = 0; buffer[1] = 7; bref2 = cbit_ref(&buffer[0], sizeof(buffer)); fixed_bitstring<16> bstr3; bstr3.unpack(bref2); TESTASSERT(bstr3 == "0000000000000111"); TESTASSERT(bstr3.to_string() == "0000000000000111"); return 0; } int test_seq_of() { uint8_t buf[1024]; memset(buf, 0, 1024); bit_ref b(&buf[0], sizeof(buf)); bit_ref borig = b; cbit_ref borig2(&buf[0], sizeof(buf)); uint32_t fixed_list_size = 33; std::array fixed_list; for (uint32_t i = 0; i < fixed_list_size; ++i) { fixed_list[i] = i; } { // test copy and == std::array fixed_list2 = fixed_list; TESTASSERT(fixed_list == fixed_list2); } int lb = 0, ub = 40; uint32_t n_bits = ceil(log2(ub - lb + 1)); pack_fixed_seq_of(b, &fixed_list[0], fixed_list.size(), integer_packer(lb, ub, false)); TESTASSERT(b.distance(borig) == (int)(fixed_list_size * n_bits)); cbit_ref b2(&buf[0], sizeof(buf)); std::array fixed_list2; unpack_fixed_seq_of(&fixed_list2[0], b2, fixed_list.size(), integer_packer(lb, ub, false)); TESTASSERT(fixed_list == fixed_list2); // bounded seq_of bounded_array bseq; TESTASSERT(bseq.size() == 0); bseq.resize(fixed_list_size); TESTASSERT(bseq.size() == fixed_list_size); memcpy(&bseq[0], &fixed_list[0], fixed_list_size * sizeof(uint32_t)); b = borig; pack_dyn_seq_of(b, bseq, 0, 33, integer_packer(lb, ub, false)); TESTASSERT(b.distance(borig) == (int)((fixed_list_size + 1) * n_bits)); // unaligned // TESTASSERT(b.distance(borig)==fixed_list_size*n_bits+8); // aligned bounded_array bseq2; bseq2.resize(fixed_list_size); b2 = borig2; unpack_dyn_seq_of(bseq2, b2, 0, 33, integer_packer(lb, ub, false)); TESTASSERT(bseq2 == bseq); TESTASSERT(std::equal(&bseq2[0], &bseq2[fixed_list_size], &fixed_list[0])); { bounded_array bseq3; bseq3 = bseq; TESTASSERT(bseq == bseq3); // call dtor } TESTASSERT(bseq2 == bseq); // dynamic array dyn_array vec, vec2(33); std::iota(vec2.begin(), vec2.end(), 0); std::shuffle(vec2.begin(), vec2.end(), g); TESTASSERT(vec2.size() == 33); TESTASSERT(vec.size() == 0); vec.resize(32); std::iota(vec.begin(), vec.end(), 0); std::shuffle(vec.begin(), vec.end(), g); TESTASSERT(vec.size() == 32); vec[5] = 5; vec.push_back(33); TESTASSERT(vec.size() == 33); TESTASSERT(vec[5] == 5); // resize does not affect content int* pos = &vec[5]; vec.resize(10); TESTASSERT(vec.size() == 10); // reduction in size does not cause realloc TESTASSERT(pos == &vec[5]); { dyn_array vec3 = vec2; TESTASSERT(vec3.size() == vec2.size()); TESTASSERT(std::equal(vec3.begin(), vec3.end(), vec2.begin())); vec3 = vec; TESTASSERT(vec3.size() == vec.size()); TESTASSERT(std::equal(vec3.begin(), vec3.end(), vec.begin())); } TESTASSERT(vec[5] == 5); return 0; } int test_copy_ptr() { typedef fixed_octstring<10> TestType; char buffer[1024]; uint32_t N = 10; for (uint32_t i = 0; i < N; ++i) { buffer[i] = i; } TestType* s = new fixed_octstring<10>(); copy_ptr cptr(s); copy_ptr cptr2; memcpy(&(*cptr)[0], buffer, N); TESTASSERT(cptr2.get() == NULL); TESTASSERT(memcmp(&(*s)[0], buffer, s->size()) == 0); TESTASSERT(*cptr == *s); TESTASSERT(cptr.get() == s); TESTASSERT(memcmp(&(*cptr)[0], buffer, cptr->size()) == 0); TESTASSERT(cptr2.get() == NULL); TESTASSERT(cptr.get() != NULL); { copy_ptr cptr3 = cptr; TESTASSERT(cptr3 == cptr); TESTASSERT(*cptr3 == *s); TESTASSERT(cptr3.get() != cptr.get()); // different addresses TESTASSERT(memcmp(&(*cptr3)[0], buffer, cptr3->size()) == 0); // call dtor } TESTASSERT(*cptr == *s); // Test make_copy_ptr() function. It has the potential to hide all news from the code. TestType s2(*s); copy_ptr cptr3 = make_copy_ptr(s2); TESTASSERT(cptr3.get() != &s2); TESTASSERT(cptr3 == cptr); // get raw pointer and delete manually TestType* s3 = cptr.release(); TESTASSERT(s3 == s); // same address delete s3; // it should *not* double free return 0; } class EnumTest { public: enum options { test5, test10, test20, nulltype }; options value; static const uint32_t nof_types = 3, nof_exts = 0; static const bool has_ext = false; EnumTest() {} EnumTest(options v) : value(v) {} EnumTest& operator=(options v) { value = v; return *this; } operator uint8_t() { return (uint8_t)value; } std::string to_string() const { switch (value) { case test5: return "test5"; case test10: return "test10"; case test20: return "test20"; default: printf("invalid value\n"); } return ""; } int32_t to_number() const { switch (value) { case test5: return 5; case test10: return 10; case test20: return 20; default: printf("invalid value\n"); } return -1; } }; int test_enum() { EnumTest e; EnumTest e2; e = EnumTest::test10; TESTASSERT(e.nof_types == 3); TESTASSERT(e.to_string() == "test10"); TESTASSERT(e.to_number() == 10); TESTASSERT(string_to_enum(e2, "test10")); TESTASSERT(e2 == e); TESTASSERT(number_to_enum(e2, 10)); TESTASSERT(e2 == e); uint8_t buffer[1024]; bit_ref bref(&buffer[0], sizeof(buffer)); bit_ref borig = bref; TESTASSERT(pack_enum(bref, e) == SRSASN_SUCCESS); TESTASSERT(bref.distance(borig) == (int)(floor(log2(e.nof_types)) + 1)); cbit_ref bref2(&buffer[0], sizeof(buffer)); TESTASSERT(unpack_enum(e2, bref2) == SRSASN_SUCCESS); TESTASSERT(bref2.distance() == (int)bref.distance()); TESTASSERT(e == e2); // Test fail path TESTASSERT(test_spy->get_error_counter() == 0 and test_spy->get_warning_counter() == 0); bref = bit_ref(&buffer[0], sizeof(buffer)); bref2 = cbit_ref(&buffer[0], sizeof(buffer)); e = EnumTest::nulltype; TESTASSERT(pack_enum(bref, e) == SRSASN_ERROR_ENCODE_FAIL); buffer[0] = 255; TESTASSERT(unpack_enum(e, bref2) == SRSASN_ERROR_DECODE_FAIL); TESTASSERT(test_spy->get_error_counter() == 2 and test_spy->get_warning_counter() == 0); return 0; } int test_json_writer() { json_writer writer; writer.start_array(""); writer.start_obj(""); writer.start_obj("obj1"); writer.write_str("field1", "01010101"); writer.write_int("field2", 5); writer.write_bool("field3", true); writer.start_obj("obj2"); writer.write_int("field4", 1); writer.start_obj("obj3"); writer.end_obj(); writer.start_array("array1"); writer.end_array(); writer.end_obj(); writer.end_obj(); writer.end_obj(); writer.end_array(); printf("%s\n", writer.to_string().c_str()); return 0; } int test_big_integers() { integer big_integer = 3172073535; uint8_t mem_chunk[128]; bit_ref bref(&mem_chunk[0], sizeof(mem_chunk)); TESTASSERT(big_integer.pack(bref) == 0); uint8_t bytes[] = {0xC0, 0xBD, 0x12, 0x00, 0x3F}; TESTASSERT(memcmp(bytes, mem_chunk, sizeof(bytes)) == 0); integer big_integer2; cbit_ref cbref(mem_chunk, sizeof(mem_chunk)); TESTASSERT(big_integer2.unpack(cbref) == 0); TESTASSERT(big_integer == big_integer2); return 0; } int main() { // Setup the log spy to intercept error and warning log entries. if (!srslog::install_custom_sink( srsran::log_sink_spy::name(), std::unique_ptr(new srsran::log_sink_spy(srslog::get_default_log_formatter())))) { return SRSRAN_ERROR; } test_spy = static_cast(srslog::find_sink(srsran::log_sink_spy::name())); if (!test_spy) { return SRSRAN_ERROR; } auto& asn1_logger = srslog::fetch_basic_logger("ASN1", *test_spy, false); asn1_logger.set_level(srslog::basic_levels::debug); asn1_logger.set_hex_dump_max_size(-1); // Start the log backend. srslog::init(); TESTASSERT(test_arrays() == 0); TESTASSERT(test_bit_ref() == 0); TESTASSERT(test_oct_string() == 0); TESTASSERT(test_bitstring() == 0); TESTASSERT(test_seq_of() == 0); TESTASSERT(test_copy_ptr() == 0); TESTASSERT(test_enum() == 0); TESTASSERT(test_big_integers() == 0); // TESTASSERT(test_json_writer()==0); srslog::flush(); printf("Success\n"); }