Pinging this because I'd like this to go forward to make testing easier. I know folks have concerns about maintaining completeness of the scripting APIs and about keeping the test suite debuggable. I just don't think making FileCheck available in inline tests is counter to those goals :).
I think this boils down to having a more powerful replacement for `self.expect` in lldbinline tests. As we're actively discouraging use of pexpect during code review now, we need some replacement. vedant > On Aug 15, 2018, at 12:18 PM, Vedant Kumar <v...@apple.com> wrote: > > > >> On Aug 15, 2018, at 12:12 PM, Jason Molenda <jmole...@apple.com> wrote: >> >> >> >>> On Aug 15, 2018, at 11:34 AM, Vedant Kumar <v...@apple.com> wrote: >>> >>> >>> >>>> On Aug 14, 2018, at 6:19 PM, Jason Molenda <jmole...@apple.com> wrote: >>>> >>>> It's more verbose, and it does mean test writers need to learn the public >>>> API, but it's also much more stable and debuggable in the future. >>> >>> I'm not sure about this. Having looked at failing sb api tests for a while >>> now, I find them about as easy to navigate and fix as FileCheck tests in >>> llvm. >> >> I don't find that to be true. I see a failing test on line 79 or whatever, >> and depending on what line 79 is doing, I'll throw in some >> self.runCmd("bt")'s or self.runCmd("fr v") to the test, re-run, and see what >> the relevant context is quickly. For most simple tests, I can usually spot >> the issue in under a minute. dotest.py likes to eat output when it's run in >> multiprocess mode these days, so I have to remember to add >> --no-multiprocess. If I'm adding something that I think is generally useful >> to debug the test case, I'll add a conditional block testing again >> self.TraceOn() and print things that may help people who are running >> dotest.py with -t trace mode enabled. > > I do agree that there are effective ways of debugging sb api tests. Having > worked with plenty of filecheck-based tests in llvm/clang/swift, I find them > to be as easy (or easier for me personally) to debug. > > >> Sometimes there is a test written so it has a "verify this value" function >> that is run over a variety of different variables during the test timeframe, >> and debugging that can take a little more work to understand the context >> that is failing. But that kind of test would be harder (or at least much >> more redundant) to express in a FileCheck style system anyway, so I can't >> ding it. > > > Yep, sounds like a great candidate for a unit test or an SB API test. > > >> As for the difficulty of writing SB API tests, you do need to know the >> general architecture of lldb (a target has a process, a process has threads, >> a thread has frames, a frame has variables), the public API which quickly >> becomes second nature because it is so regular, and then there's the >> testsuite specific setup and template code. But is that that intimidating >> to anyone familiar with lldb? > > Not intimidating, no. Cumbersome and slow, absolutely. So much so that I > don't see a way of adequately testing my patches this way. It would just take > too much time. > > vedant > >> packages/Python/lldbsuite/test/sample_test/TestSampleTest.py is 50 lines >> including comments; there's about ten lines of source related to >> initializing / setting up the testsuite, and then 6 lines is what's needed >> to run to a breakpoint, get a local variable, check the value. >> >> >> J >> >> >> >>> >>> >>>> It's a higher up front cost but we're paid back in being able to develop >>>> lldb more quickly in the future, where our published API behaviors are >>>> being tested directly, and the things that must not be broken. >>> >>> I think the right solution here is to require API tests when new >>> functionality is introduced. We can enforce this during code review. Making >>> it impossible to write tests against the driver's output doesn't seem like >>> the best solution. It means that far fewer tests will be written (note that >>> a test suite run of lldb gives less than 60% code coverage). It also means >>> that the driver's output isn't tested as much as it should be. >>> >>> >>>> The lldb driver's output isn't a contract, and treating it like one makes >>>> the debugger harder to innovate in the future. >>> >>> I appreciate your experience with this (pattern matching on driver input) >>> in gdb. That said, I think there are reliable/maintainable ways to do this, >>> and proven examples we can learn from in llvm/clang/etc. >>> >>> >>>> It's also helpful when adding new features to ensure you've exposed the >>>> feature through the API sufficiently. The first thing I thought to try >>>> when writing the example below was SBFrame::IsArtificial() (see >>>> SBFrame::IsInlined()) which doesn't exist. If a driver / IDE is going to >>>> visually indicate artificial frames, they'll need that. >>> >>> Sure. That's true, we do need API exposure for new features, and again we >>> can enforce that during code review. The reason you didn't find >>> IsArtificial() is because it's sitting on my disk :). Haven't shared the >>> patch yet. >>> >>> vedant >>> >>>> >>>> J >>>> >>>>> On Aug 14, 2018, at 5:56 PM, Vedant Kumar <v...@apple.com> wrote: >>>>> >>>>> It'd be easy to update FileCheck tests when changing the debugger (this >>>>> happens all the time in clang/swift). OTOH, the verbosity of the python >>>>> API means that fewer tests get written. I see a real need to make >>>>> expressive tests easier to write. >>>>> >>>>> vedant >>>>> >>>>>> On Aug 14, 2018, at 5:38 PM, Jason Molenda <jmole...@apple.com> wrote: >>>>>> >>>>>> I'd argue against this approach because it's exactly why the lit tests >>>>>> don't run against the lldb driver -- they're hardcoding the output of >>>>>> the lldb driver command into the testsuite and these will eventually >>>>>> make it much more difficult to change and improve the driver as we've >>>>>> accumulated this style of test. >>>>>> >>>>>> This is a perfect test for a normal SB API. Run to your breakpoints and >>>>>> check the stack frames. >>>>>> >>>>>> f0 = thread.GetFrameAtIndex(0) >>>>>> check that f0.GetFunctionName() == sink >>>>>> check that f0.IsArtifical() == True >>>>>> check that f0.GetLineEntry().GetLine() == expected line number >>>>>> >>>>>> >>>>>> it's more verbose, but it's also much more explicit about what it's >>>>>> checking, and easy to see what has changed if there is a failure. >>>>>> >>>>>> >>>>>> J >>>>>> >>>>>>> On Aug 14, 2018, at 5:31 PM, Vedant Kumar via lldb-dev >>>>>>> <lldb-dev@lists.llvm.org> wrote: >>>>>>> >>>>>>> Hello, >>>>>>> >>>>>>> I'd like to make FileCheck available within lldb inline tests, in >>>>>>> addition to existing helpers like 'runCmd' and 'expect'. >>>>>>> >>>>>>> My motivation is that several tests I'm working on can't be made as >>>>>>> rigorous as they need to be without FileCheck-style checks. In >>>>>>> particular, the 'matching', 'substrs', and 'patterns' arguments to >>>>>>> runCmd/expect don't allow me to verify the ordering of checked input, >>>>>>> to be stringent about line numbers, or to capture & reuse snippets of >>>>>>> text from the input stream. >>>>>>> >>>>>>> I'd curious to know if anyone else is interested or would be willing to >>>>>>> review this (https://reviews.llvm.org/D50751). >>>>>>> >>>>>>> Here's an example of an inline test which benefits from FileCheck-style >>>>>>> checking. This test is trying to check that certain frames appear in a >>>>>>> backtrace when stopped inside of the "sink" function. Notice that >>>>>>> without FileCheck, it's not possible to verify the order in which >>>>>>> frames are printed, and that dealing with line numbers would be >>>>>>> cumbersome. >>>>>>> >>>>>>> ``` >>>>>>> --- >>>>>>> a/lldb/packages/Python/lldbsuite/test/functionalities/tail_call_frames/unambiguous_sequence/main.cpp >>>>>>> +++ >>>>>>> b/lldb/packages/Python/lldbsuite/test/functionalities/tail_call_frames/unambiguous_sequence/main.cpp >>>>>>> @@ -9,16 +9,21 @@ >>>>>>> >>>>>>> volatile int x; >>>>>>> >>>>>>> +// CHECK: frame #0: {{.*}}sink() at main.cpp:[[@LINE+2]] [opt] >>>>>>> void __attribute__((noinline)) sink() { >>>>>>> - x++; //% self.expect("bt", substrs = ['main', 'func1', 'func2', >>>>>>> 'func3', 'sink']) >>>>>>> + x++; //% self.filecheck("bt", "main.cpp") >>>>>>> } >>>>>>> >>>>>>> +// CHECK-NEXT: frame #1: {{.*}}func3() {{.*}}[opt] [artificial] >>>>>>> void __attribute__((noinline)) func3() { sink(); /* tail */ } >>>>>>> >>>>>>> +// CHECK-NEXT: frame #2: {{.*}}func2() at main.cpp:[[@LINE+1]] [opt] >>>>>>> void __attribute__((disable_tail_calls, noinline)) func2() { func3(); >>>>>>> /* regular */ } >>>>>>> >>>>>>> +// CHECK-NEXT: frame #3: {{.*}}func1() {{.*}}[opt] [artificial] >>>>>>> void __attribute__((noinline)) func1() { func2(); /* tail */ } >>>>>>> >>>>>>> +// CHECK-NEXT: frame #4: {{.*}}main at main.cpp:[[@LINE+2]] [opt] >>>>>>> int __attribute__((disable_tail_calls)) main() { >>>>>>> func1(); /* regular */ >>>>>>> return 0; >>>>>>> ``` >>>>>>> >>>>>>> For reference, here's the output of the "bt" command: >>>>>>> >>>>>>> ``` >>>>>>> runCmd: bt >>>>>>> output: * thread #1, queue = 'com.apple.main-thread', stop reason = >>>>>>> breakpoint 1.1 >>>>>>> * frame #0: 0x000000010c6a6f64 a.out`sink() at main.cpp:14 [opt] >>>>>>> frame #1: 0x000000010c6a6f70 a.out`func3() at main.cpp:15 [opt] >>>>>>> [artificial] >>>>>>> frame #2: 0x000000010c6a6f89 a.out`func2() at main.cpp:21 [opt] >>>>>>> frame #3: 0x000000010c6a6f90 a.out`func1() at main.cpp:21 [opt] >>>>>>> [artificial] >>>>>>> frame #4: 0x000000010c6a6fa9 a.out`main at main.cpp:28 [opt] >>>>>>> ``` >>>>>>> >>>>>>> thanks, >>>>>>> vedant >>>>>>> _______________________________________________ >>>>>>> lldb-dev mailing list >>>>>>> lldb-dev@lists.llvm.org >>>>>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev
_______________________________________________ lldb-dev mailing list lldb-dev@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev