From 4628b6de8e735505be07b996c997effb9f399820 Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Tue, 11 Sep 2018 20:48:34 -0400 Subject: [PATCH] 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 --- .../kits/interface/InterfaceKitTestAddon.cpp | 2 + src/tests/kits/interface/Jamfile | 4 + src/tests/kits/interface/bmenu/MenuTest.cpp | 84 +++++++++++++++++++ src/tests/kits/interface/bmenu/MenuTest.h | 10 +++ 4 files changed, 100 insertions(+) create mode 100644 src/tests/kits/interface/bmenu/MenuTest.cpp create mode 100644 src/tests/kits/interface/bmenu/MenuTest.h diff --git a/src/tests/kits/interface/InterfaceKitTestAddon.cpp b/src/tests/kits/interface/InterfaceKitTestAddon.cpp index f3d26e53a7..37943cf1f1 100644 --- a/src/tests/kits/interface/InterfaceKitTestAddon.cpp +++ b/src/tests/kits/interface/InterfaceKitTestAddon.cpp @@ -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()); diff --git a/src/tests/kits/interface/Jamfile b/src/tests/kits/interface/Jamfile index 724b5c71ed..29a6c45b53 100644 --- a/src/tests/kits/interface/Jamfile +++ b/src/tests/kits/interface/Jamfile @@ -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 diff --git a/src/tests/kits/interface/bmenu/MenuTest.cpp b/src/tests/kits/interface/bmenu/MenuTest.cpp new file mode 100644 index 0000000000..1a095c3efb --- /dev/null +++ b/src/tests/kits/interface/bmenu/MenuTest.cpp @@ -0,0 +1,84 @@ +/* + * Copyright 2018, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Augustin Cavalier + */ +#include "../common.h" + + +#include +#include +#include +#include +#include + + +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( + "BMenu_Size", &MenuTestcase::SizeTest)); + testSuite->addTest(new CppUnit::TestCaller( + "BMenu_ConcurrencyAbuse", &MenuTestcase::ConcurrencyAbuseTest)); + + return testSuite; +} diff --git a/src/tests/kits/interface/bmenu/MenuTest.h b/src/tests/kits/interface/bmenu/MenuTest.h new file mode 100644 index 0000000000..1f9fed6e0b --- /dev/null +++ b/src/tests/kits/interface/bmenu/MenuTest.h @@ -0,0 +1,10 @@ +#ifndef _menu_test_h_ +#define _menu_test_h_ + +class CppUnit::Test; + +CppUnit::Test* MenuTestSuite(); + +#endif // _menu_test_h_ + +