I am running an experiment in trying to link google test to ada95 for unit testing. I know ada has aunit and ahven, but this is just to see if this is possible and is outside of the scope of my question. I have successfully been able to do simple functions and procedures with the basic data types. The next thing I would like to try to do is similar to the following:
Here is the main.cpp file:
#include <stdio.h>
#include <gtest/gtest.h>
extern "C" {
int firstElement(int buffer[]);
}
TEST(tryTest, checkBuffer){
int buffer[10] = {10,1,6,4,3,2,1,3,4,6};
ASSERT_EQ(buffer[0],firstElement(buffer));
}
int main(int argc, char ** argv) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
for simplicity I will just put the ads file:
Lib_test.ads
with Interfaces.C;
with Interfaces.C.Pointers;
package Lib_Test is
function FirstElement(a: Interfaces.C.Pointers) return Interfaces.C.Int;
pragma Export(C,FirstElement,"firstElement");
end Lib_Test;
I know in c you are passing in the pointer to the first element not the entire array for the function. That is why I tried to use Interfaces.C.Pointers for the data type but I got the following error
subtype mark required in this context
found "Pointers" declared at i-cpoint.ads:44
I have not found a good example of using other array types besides char arrays. Can someone show me how I can use Interfaces.C.Pointers for an integer array or even how I can fix this, I believe it is just my data type in the parameter of the function. I want to be able to access the c integer array in the ada function.
Thank you all!
According to RM B.3 (70):
An Ada parameter of an array type with component type T, of any mode, is passed as a t* argument to a C function, where t is the C type corresponding to the Ada type T.
Hence, there's no need to use package Interfaces.C.Pointers
. You can just use an Ada array type. A small example:
main.cpp
#include <stdio.h>
#include <gtest/gtest.h>
extern "C" {
void testinit();
void testfinal();
int firstElement(int *buffer);
}
class MyTest : public ::testing::Test {
protected:
MyTest() {
testinit(); // Initialize the Ada library
}
~MyTest() override {
testfinal(); // Finalize the Ada library
}
};
TEST_F(MyTest, CheckBuffer) {
int buffer[10] = {10,1,6,4,3,2,1,3,4,6};
ASSERT_EQ(buffer[0], firstElement(buffer));
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
test.gpr
with "libtest";
project Test is
for Source_Dirs use ("src");
for Object_Dir use "obj";
for Main use ("main.cpp");
for Languages use ("C++");
package Compiler is
for Switches ("c++") use ("-I/usr/src/googletest/googletest/include");
end Compiler;
package Linker is
for Switches ("c++") use ("-lgtest", "-lgtest_main", "-pthread", "-ltest");
end Linker;
end Test;
lib_test.ads
with Interfaces.C;
package Lib_Test is
package C renames Interfaces.C;
type Seq is array (0 .. 9) of C.Int;
function First_Element (A : Seq) return C.Int;
pragma Export (C, First_Element, "firstElement");
end Lib_Test;
lib_test.adb
package body Lib_Test is
-------------------
-- First_Element --
-------------------
function First_Element (A : Seq) return C.Int is
begin
return A (A'First);
end First_Element;
end Lib_Test;
libtest.gpr
library project Libtest is
for Library_Kind use "dynamic";
for Library_Name use "test";
for Library_Interface use ("lib_test");
for Library_Auto_Init use "False";
for Library_Dir use "lib";
for Object_Dir use "obj";
for Source_Dirs use ("src");
end Libtest;
output
$ ./obj/main
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from MyTest
[ RUN ] MyTest.CheckBuffer
[ OK ] MyTest.CheckBuffer (0 ms)
[----------] 1 test from MyTest (0 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (0 ms total)
[ PASSED ] 1 test.
In addition to the complete answer by @DeeDee: In the case you truly wanted only the first element, since you're receiving a pointer to int, any of the following Ada declarations should work (not tested!!):
function First_Element (A : in out C.int) return C.Int;
-- An in/out argument exported with C convention should
-- use a pointer underneath.
function First_Element (A : aliased C.int) return C.Int;
-- Not sure this is already in Ada 95. By marking the
-- argument aliased, it's passed by reference.
function First_Element (A : access C.int) return C.Int;
-- Explicit pointer. I don't like this one (too low level),
-- but it's a possibility.
The key idea to take away from your question is to use the actual pointee type and then ensure some kind of pass-by-reference mode is used.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With