Skip to content
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

WIP: Begin test coverage #167

Open
2 of 3 tasks
Tracked by #163 ...
nathanjhood opened this issue Dec 13, 2024 · 4 comments
Open
2 of 3 tasks
Tracked by #163 ...

WIP: Begin test coverage #167

nathanjhood opened this issue Dec 13, 2024 · 4 comments
Assignees
Labels
tests Improvements or additions to Catch2 unit tests and CTest

Comments

@nathanjhood
Copy link
Member

nathanjhood commented Dec 13, 2024

@nathanjhood nathanjhood mentioned this issue Dec 13, 2024
6 tasks
@nathanjhood nathanjhood self-assigned this Dec 13, 2024
@nathanjhood nathanjhood added the tests Improvements or additions to Catch2 unit tests and CTest label Dec 13, 2024
@nathanjhood nathanjhood moved this from Done to In Progress in StoneyDSP Dec 13, 2024
@nathanjhood nathanjhood changed the title Begin test coverage WIP: Begin test coverage Dec 13, 2024
@nathanjhood nathanjhood reopened this Dec 13, 2024
@nathanjhood
Copy link
Member Author

  • instance constructs/deconstructs safely

Having some real trouble with this; the Module structs are fine, since they do nothing particular in their deconstructors.

The Widgets and ModuleWidgets however, are loaded with new when constructing, and some hidden delete pattern in their parent-class deconstructors.

When attempting to construct/deconstruct instances naively (new/delete) within unit test code, the test fails with a SIGABRT.

The same thing happens when using shared pointers?

I'd prefer to be using:

  • smart pointers
  • initializer lists
  • clean, or at least visible, deconstructors

I am blocked a bit by hesitance; I don't fully understand the "quirks" about held resources and Rack For DAW's... So, the design system deep-dive shall take precedence, before I can create satisfactory unit tests on this.

@nathanjhood
Copy link
Member Author

When attempting to construct/deconstruct instances naively (new/delete) within unit test code, the test fails with a SIGABRT.

I suppose we could always test to make sure that it fails with a SIGABRT :)

@nathanjhood
Copy link
Member Author

I've had a clue about getting a test fixture working - it turns out, Rack's main() is not shipped with the SDK - d'Oh! It can be found in the source tree under adapters/standalone.cpp...

It's a pretty hefty entry point; instead of abstracting the startup routine into their own start() or similar, it's just raw-dogged right there inside the main() function body; seems there are preprocessor logic switches and even wmain() for -DUNICODE.... which was confusing me way back at the beginning of all this. Nice to have found the reference impl for Rack.

I need to create some kind of local, altered copy of this file which starts Catch2 on-demand within Rack's main()...

@nathanjhood
Copy link
Member Author

nathanjhood commented Jan 22, 2025

I need to create some kind of local, altered copy of this file which starts Catch2 on-demand within Rack's main()...

Cool - I just literally copied adapters/standalone.cpp into my source tree, and added it's build step to the bottom of my Makefile, and edited to take libRack from the vcpkg directory instead:

# Standalone adapter

STANDALONE_SOURCES += test/Adapter.cpp

ifdef ARCH_LIN
	STANDALONE_TARGET := Rack
	STANDALONE_LDFLAGS += -static-libstdc++ -static-libgcc
	STANDALONE_LDFLAGS += -Wl,-rpath=.
	STANDALONE_LIB := libRack.so
endif
ifdef ARCH_MAC
	STANDALONE_TARGET := Rack
	STANDALONE_LDFLAGS += -stdlib=libc++
	STANDALONE_LIB := libRack.dylib
endif
ifdef ARCH_WIN
	STANDALONE_TARGET := Rack.exe
	STANDALONE_LDFLAGS += -mwindows
	# 1MiB stack size to match MSVC
	STANDALONE_LDFLAGS += -Wl,--stack,0x100000
	STANDALONE_OBJECTS += build/Rack.res
	STANDALONE_LIB := libRack.dll
endif

STANDALONE_OBJECTS += $(PWD)/build/vcpkg_installed/$(TRIPLET_ARCH)-$(TRIPLET_OS)/lib/$(STANDALONE_LIB)

$(STANDALONE_TARGET): $(STANDALONE_SOURCES) $(STANDALONE_OBJECTS)
	$(CXX) $(CXXFLAGS) -o $@ $^ $(STANDALONE_LDFLAGS)

I just did make Rack and it built. The application runs successfully, but is lacking configuration (system/user dir etc) so I'm greeted with the option of blowing away my last scene to continue.

I'll make some space for a new, improved test executable.

The additional cool thing about this: when building this executable with -DDEBUG, I can overload the global and Widget-level new and delete operators to also keep a map or list of pointers that were allocated in this way.

::std::unordered_map<void*, size_t> allocationMap;

void* operator new(size_t size)
{
  void* ptr = ::std::malloc(size);
  allocationMap[ptr] = size;
  return ptr;
}

void operator delete(void* ptr) noexcept
{
  allocationMap.erase(ptr);
  ::std::free(ptr);
}

When the program goes into it's shutdown mode, before exiting main(), we can check the status of the map; any remaining entries are, in theory, data leaks, and probably traceable with the right debugger skills.

int main()
{
  // run Rack...

  // ..before closing:
  if (!allocationMap.empty())
    {
        DEBUG("Memory leaks detected:");  // use Rack's DEBUG macro and underlying rack::logger...

        for (const auto& pair : allocationMap) {
           DEBUG("Leaked address: %s", ::std::string(pair.first).c_str()); 
           DEBUG("Leak size: %s", ::std::string(pair.second).c_str());
        }

    } else {
        DEBUG("No memory leaks detected.");
    }

  return; // as usual...
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
tests Improvements or additions to Catch2 unit tests and CTest
Projects
Status: In Progress
Development

No branches or pull requests

1 participant