-
Notifications
You must be signed in to change notification settings - Fork 445
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add an example gtest case, useful for unit-testing compiler pass #434
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This example does not show why doing tests this way is useful.
test/gtest/helper.h
Outdated
#include <string> | ||
|
||
/* preprocessing by prepending the content of core.p4 to test program */ | ||
std::string with_core_p4 (std::string pgm) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this should be read from the file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, since you don't mutate pgm
, it's probably better to make it a const std::string&
.
I agree it'd be best to read core.p4
from the file once when the GTest executable starts (so in main()
). We can then reuse it for every invocation of with_core_p4
. If that's not quick to do, though, I think it'd be fine to do this now and file a followup issue to fix that later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
@@ -0,0 +1,62 @@ | |||
/* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is more or less what the compiler is doing now.
It would be much easier to add a flag for the compiler to stop compiling after a certain pass.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For unit tests, we want as much control as possible. I think we're better off using an approach like this. It gives us maximum flexibility, and it has the advantage of not invoking cpp
for every unit test.
frontends/p4/p4-parse.ypp
Outdated
@@ -993,6 +993,18 @@ const IR::P4Program *parse_P4_16_file(const char *name, FILE *in) { | |||
return new IR::P4Program(declarations->srcInfo, declarations); | |||
} | |||
|
|||
const IR::P4Program *parse_string(std::string &pgm) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const std::string&
is probably preferable, since it doesn't look like you mutate pgm
in here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! Just needs a few tweaks.
test/gtest/helper.h
Outdated
#include <string> | ||
|
||
/* preprocessing by prepending the content of core.p4 to test program */ | ||
std::string with_core_p4 (std::string pgm) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, since you don't mutate pgm
, it's probably better to make it a const std::string&
.
I agree it'd be best to read core.p4
from the file once when the GTest executable starts (so in main()
). We can then reuse it for every invocation of with_core_p4
. If that's not quick to do, though, I think it'd be fine to do this now and file a followup issue to fix that later.
@@ -0,0 +1,62 @@ | |||
/* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For unit tests, we want as much control as possible. I think we're better off using an approach like this. It gives us maximum flexibility, and it has the advantage of not invoking cpp
for every unit test.
"parser Parser<H, M> (packet_in p){ state start{} };\n" | ||
"control empty() { apply {} };\n" | ||
"package top(empty e);\n" | ||
"top(empty()) main;\n"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
C++11's raw string literals might make this a little nicer. (And we can use them!)
test/gtest/typecheck_test.cpp
Outdated
"top(empty()) main;\n"); | ||
|
||
const IR::P4Program* pgm = parse_string(program); | ||
ASSERT_TRUE(pgm != nullptr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ASSERT_NE(nullptr, pgm);
is better; GTest can give much nicer log messages in that case.
test/gtest/typecheck_test.cpp
Outdated
|
||
pgm = pgm->apply(passes); | ||
|
||
ASSERT_TRUE(pgm != nullptr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above.
@mbudiu-vmw, this kind of test is useful for a number of reasons:
In addition, tests written this way have less overhead than our current approach to writing tests, which will speed up our test suite over the long term. |
However;
One would need some sort of pattern-matching language for writing readable IR-based tests. |
It's true that you won't have syntax highlighting, but some tradeoffs always have to be made. Regarding the issue of everything being rebuilt when you touch a Makefile, that is true, but we can easily have as many tests as we want in a single source file. Adding a new GTest will often not require touching a Makefile at all. Right now we don't have a lot of GTests, so new tests generally don't have an existing file that they'd logically belong in, but over time I expect that most tests will find a natural home in an existing file. |
Regarding @mbudiu-vmw's first point |
I think there are many times when that'd be appropriate, but there are massive readability benefits to seeing the P4 code right there inside the test, so for short snippets I'd actually prefer this approach. We should make the decision on a case-by-case basis, I think. |
What I don't yet understand is how in-complete p4 programs are tested in testdata/p4_16_samples/. For example,
|
I agree with @antoninbas that if a p4 program is complete, then it should be read from a file, and tested with existing test scripts. But if a program is a fragment, then unit-test would be helpful. |
test/gtest/helper.h
Outdated
@@ -17,7 +17,7 @@ limitations under the License. | |||
#include <string> | |||
|
|||
/* preprocessing by prepending the content of core.p4 to test program */ | |||
std::string with_core_p4 (std::string pgm) { | |||
std::string with_core_p4 (const std::string pgm) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const std::string&
please. =)
You can't really test incomplete programs. |
test/gtest/helper.h
Outdated
@@ -17,7 +17,7 @@ limitations under the License. | |||
#include <string> | |||
|
|||
/* preprocessing by prepending the content of core.p4 to test program */ | |||
std::string with_core_p4 (const std::string pgm) { | |||
std::string with_core_p4 (const std::string& pgm) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
|
||
/* preprocessing by prepending the content of core.p4 to test program */ | ||
std::string with_core_p4 (const std::string& pgm) { | ||
std::ifstream input("p4include/core.p4"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This relies on running the test in the build directory -- since that is what generally happens, perhaps ok?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I don't think make check
works outside the build directory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
gtest will work in both p4c
and p4c/build
.
No description provided.