tests/interface: Add a (currently crashing) BMenu "concurrency" test.

Adds/removes items as rapidly as possible from the menu from the
main thread while the menu is open. That part works. Then it deletes
all of the BMenuItems and then closes the menu, which crashes,
as the BMenuItems do not notify the BMenu they are being deleted.

I tested this on BeOS and it seems that this model crashes there also
(looking through the code comments, it seems there are a number of
testcases found throughout the years like this.) Removing the items
before deleting them indeed fixes the crashes on both BeOS
and Haiku.

Change-Id: I8624f966bdc17030ddca05b97aa57b518ab420c5
Reviewed-on: https://review.haiku-os.org/540
Reviewed-by: waddlesplash <waddlesplash@gmail.com>
This commit is contained in:
Augustin Cavalier 2018-09-11 20:48:34 -04:00 committed by waddlesplash
parent 81d0a0e0a7
commit 4628b6de8e
4 changed files with 100 additions and 0 deletions

View File

@ -6,6 +6,7 @@
#include "bbitmap/BitmapTest.h"
#include "bdeskbar/DeskbarTest.h"
#include "bpolygon/PolygonTest.h"
#include "bmenu/MenuTest.h"
#include "bregion/RegionTest.h"
#include "btextcontrol/TextControlTest.h"
#include "btextview/TextViewTest.h"
@ -24,6 +25,7 @@ getTestSuite()
suite->addTest("BBitmap", BitmapTestSuite());
suite->addTest("BDeskbar", DeskbarTestSuite());
suite->addTest("BOutlineListView", OutlineListViewTestSuite());
suite->addTest("BMenu", MenuTestSuite());
suite->addTest("BPolygon", PolygonTestSuite());
suite->addTest("BRegion", RegionTestSuite());
suite->addTest("BTextControl", TextControlTestSuite());

View File

@ -9,6 +9,7 @@ UsePrivateHeaders interface shared ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) balert ] ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) bbitmap ] ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) bdeskbar ] ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) bmenu ] ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) bpolygon ] ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) bregion ] ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) btextcontrol ] ;
@ -42,6 +43,9 @@ UnitTestLib libinterfacetest.so
CreatePolygonTest.cpp
MapPolygonTest.cpp
# BMenu
MenuTest.cpp
# BRegion
RegionTest.cpp
RegionTestcase.cpp

View File

@ -0,0 +1,84 @@
/*
* Copyright 2018, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Augustin Cavalier <waddlesplash>
*/
#include "../common.h"
#include <Application.h>
#include <String.h>
#include <Menu.h>
#include <MenuItem.h>
#include <PopUpMenu.h>
class MenuTestcase : public TestCase {
public:
void
SizeTest()
{
CPPUNIT_ASSERT_EQUAL(312, sizeof(BMenu));
CPPUNIT_ASSERT_EQUAL(128, sizeof(BMenuItem));
}
void
ConcurrencyAbuseTest()
{
BApplication app("application/x-vnd.Haiku-interfacekit-menutest");
BPopUpMenu* menu = new BPopUpMenu("Test");
menu->AddItem(new BMenuItem("One", NULL));
menu->AddItem(new BMenuItem("Two", NULL));
menu->AddSeparatorItem();
BMenuItem* items[10];
for (int i = 0; i < 10; i++) {
BString str;
str.SetToFormat("%d", i);
items[i] = new BMenuItem(str.String(), NULL);
}
// Now for the actual abuse.
menu->Go(BPoint(), false, true, true);
snooze(50 * 1000 /* 50 ms */);
for (int i = 0; i < 100; i++) {
for (int j = 0; j < (i % 5); j++) {
BMenuItem* item = items[(i + j) % 10];
if (item->Menu() != NULL)
continue;
menu->AddItem(item);
}
if ((i % 3) == 0) {
for (int j = 0; j < (i % 5); j++)
menu->RemoveItem((int32)0);
}
}
CPPUNIT_ASSERT_EQUAL(6, menu->CountItems());
// Cleanup.
for (int i = 0; i < 10; i++)
delete items[i];
// Close the menu.
char bytes[] = {B_ESCAPE};
menu->KeyDown(bytes, 1);
delete menu;
}
};
Test*
MenuTestSuite()
{
TestSuite* testSuite = new TestSuite();
testSuite->addTest(new CppUnit::TestCaller<MenuTestcase>(
"BMenu_Size", &MenuTestcase::SizeTest));
testSuite->addTest(new CppUnit::TestCaller<MenuTestcase>(
"BMenu_ConcurrencyAbuse", &MenuTestcase::ConcurrencyAbuseTest));
return testSuite;
}

View File

@ -0,0 +1,10 @@
#ifndef _menu_test_h_
#define _menu_test_h_
class CppUnit::Test;
CppUnit::Test* MenuTestSuite();
#endif // _menu_test_h_