#include #include #include #include #include #include #include "MinMax.hh" #include "Transition.hh" #include "Property.hh" #include "ExceptionPath.hh" #include "TimingRole.hh" #include "Scene.hh" #include "Sta.hh" #include "Sdc.hh" #include "ReportTcl.hh" #include "RiseFallMinMax.hh" #include "Variables.hh" #include "LibertyClass.hh" #include "Search.hh" #include "Path.hh" #include "PathGroup.hh" #include "PathExpanded.hh" #include "SearchPred.hh" #include "SearchClass.hh" #include "ClkNetwork.hh" #include "Mode.hh" #include "VisitPathEnds.hh" #include "search/CheckMinPulseWidths.hh" #include "search/CheckMinPeriods.hh" #include "search/CheckMaxSkews.hh" #include "search/ClkSkew.hh" #include "search/ClkInfo.hh" #include "search/Tag.hh" #include "search/PathEnum.hh" #include "search/Genclks.hh" #include "search/Levelize.hh" #include "search/Sim.hh" #include "Bfs.hh" #include "search/WorstSlack.hh" #include "search/ReportPath.hh" #include "GraphDelayCalc.hh" #include "Debug.hh" #include "PowerClass.hh" #include "search/CheckCapacitances.hh" #include "search/CheckSlews.hh" #include "search/CheckFanouts.hh" #include "search/Crpr.hh" #include "search/GatedClk.hh" #include "search/ClkLatency.hh" #include "search/FindRegister.hh" #include "search/TagGroup.hh" #include "search/MakeTimingModelPvt.hh" #include "search/CheckTiming.hh" #include "search/Latches.hh" #include "Graph.hh" #include "Liberty.hh" #include "Network.hh" namespace sta { template static void expectCallablePointerUsable(FnPtr fn) { ASSERT_NE(fn, nullptr); EXPECT_TRUE((std::is_pointer_v || std::is_member_function_pointer_v)); EXPECT_TRUE(std::is_copy_constructible_v); EXPECT_TRUE(std::is_copy_assignable_v); FnPtr fn_copy = fn; EXPECT_EQ(fn_copy, fn); } static void expectStaDesignCoreState(Sta *sta, bool design_loaded) { ASSERT_NE(sta, nullptr); EXPECT_EQ(Sta::sta(), sta); EXPECT_NE(sta->network(), nullptr); EXPECT_NE(sta->search(), nullptr); EXPECT_NE(sta->cmdSdc(), nullptr); EXPECT_FALSE(sta->scenes().empty()); if (!sta->scenes().empty()) { EXPECT_GE(sta->scenes().size(), 1); } EXPECT_NE(sta->cmdScene(), nullptr); EXPECT_TRUE(design_loaded); if (sta->network()) { EXPECT_NE(sta->network()->topInstance(), nullptr); } } // ============================================================ // StaDesignTest fixture: loads nangate45 + example1.v + clocks // Used for R8_ tests that need a real linked design with timing // ============================================================ class StaDesignTest : public ::testing::Test { protected: void SetUp() override { interp_ = Tcl_CreateInterp(); initSta(); sta_ = new Sta; Sta::setSta(sta_); sta_->makeComponents(); ReportTcl *report = dynamic_cast(sta_->report()); if (report) report->setTclInterp(interp_); Scene *corner = sta_->cmdScene(); const MinMaxAll *min_max = MinMaxAll::all(); LibertyLibrary *lib = sta_->readLiberty( "test/nangate45/Nangate45_typ.lib", corner, min_max, false); ASSERT_NE(lib, nullptr); lib_ = lib; bool ok = sta_->readVerilog("examples/example1.v"); ASSERT_TRUE(ok); ok = sta_->linkDesign("top", true); ASSERT_TRUE(ok); Network *network = sta_->network(); Instance *top = network->topInstance(); Pin *clk1 = network->findPin(top, "clk1"); Pin *clk2 = network->findPin(top, "clk2"); Pin *clk3 = network->findPin(top, "clk3"); ASSERT_NE(clk1, nullptr); ASSERT_NE(clk2, nullptr); ASSERT_NE(clk3, nullptr); PinSet *clk_pins = new PinSet(network); clk_pins->insert(clk1); clk_pins->insert(clk2); clk_pins->insert(clk3); FloatSeq *waveform = new FloatSeq; waveform->push_back(0.0f); waveform->push_back(5.0f); sta_->makeClock("clk", clk_pins, false, 10.0f, waveform, "", sta_->cmdMode()); // Set input delays Pin *in1 = network->findPin(top, "in1"); Pin *in2 = network->findPin(top, "in2"); Clock *clk = sta_->cmdSdc()->findClock("clk"); if (in1 && clk) { sta_->setInputDelay(in1, RiseFallBoth::riseFall(), clk, RiseFall::rise(), nullptr, false, false, MinMaxAll::all(), true, 0.0f, sta_->cmdSdc()); } if (in2 && clk) { sta_->setInputDelay(in2, RiseFallBoth::riseFall(), clk, RiseFall::rise(), nullptr, false, false, MinMaxAll::all(), true, 0.0f, sta_->cmdSdc()); } sta_->updateTiming(true); design_loaded_ = true; } void TearDown() override { if (sta_) expectStaDesignCoreState(sta_, design_loaded_); deleteAllMemory(); sta_ = nullptr; if (interp_) Tcl_DeleteInterp(interp_); interp_ = nullptr; } // Helper: get a vertex for a pin by hierarchical name e.g. "r1/CK" Vertex *findVertex(const char *path_name) { Network *network = sta_->cmdNetwork(); Pin *pin = network->findPin(path_name); if (!pin) return nullptr; Graph *graph = sta_->graph(); if (!graph) return nullptr; return graph->pinDrvrVertex(pin); } Pin *findPin(const char *path_name) { Network *network = sta_->cmdNetwork(); return network->findPin(path_name); } Sta *sta_; Tcl_Interp *interp_; LibertyLibrary *lib_; bool design_loaded_ = false; StringSeq group_names; }; // ============================================================ // R8_ tests: Sta.cc methods with loaded design // ============================================================ // --- vertexArrival overloads --- TEST_F(StaDesignTest, VertexArrivalMinMax) { Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); sta_->arrival(v, RiseFallBoth::riseFall(), sta_->scenes(), MinMax::max()); } TEST_F(StaDesignTest, VertexArrivalRfPathAP) { Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); Scene *corner = sta_->cmdScene(); const size_t path_idx = corner->pathIndex(MinMax::max()); (void)path_idx; sta_->arrival(v, RiseFallBoth::rise(), sta_->scenes(), MinMax::max()); } // --- vertexRequired overloads --- TEST_F(StaDesignTest, VertexRequiredMinMax) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); sta_->required(v, RiseFallBoth::riseFall(), sta_->scenes(), MinMax::max()); } TEST_F(StaDesignTest, VertexRequiredRfMinMax) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); sta_->required(v, RiseFallBoth::rise(), sta_->scenes(), MinMax::max()); } TEST_F(StaDesignTest, VertexRequiredRfPathAP) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); Scene *corner = sta_->cmdScene(); const size_t path_idx = corner->pathIndex(MinMax::max()); (void)path_idx; sta_->required(v, RiseFallBoth::rise(), sta_->scenes(), MinMax::max()); } // --- vertexSlack overloads --- TEST_F(StaDesignTest, VertexSlackMinMax) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); sta_->slack(v, MinMax::max()); } TEST_F(StaDesignTest, VertexSlackRfPathAP) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); Scene *corner = sta_->cmdScene(); const size_t path_idx = corner->pathIndex(MinMax::max()); (void)path_idx; sta_->slack(v, RiseFallBoth::rise(), sta_->scenes(), MinMax::max()); } // --- vertexSlacks --- TEST_F(StaDesignTest, VertexSlacks) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); sta_->slack(v, MinMax::max()); // Just verify it doesn't crash; values depend on timing } // --- vertexSlew overloads --- TEST_F(StaDesignTest, VertexSlewRfCornerMinMax) { Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); Scene *corner = sta_->cmdScene(); (void)corner; sta_->slew(v, RiseFallBoth::rise(), sta_->scenes(), MinMax::max()); } TEST_F(StaDesignTest, VertexSlewRfDcalcAP) { Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); Scene *corner = sta_->cmdScene(); const DcalcAPIndex dcalc_idx = corner->dcalcAnalysisPtIndex(MinMax::max()); (void)dcalc_idx; sta_->slew(v, RiseFallBoth::rise(), sta_->scenes(), MinMax::max()); } // --- vertexWorstRequiredPath --- TEST_F(StaDesignTest, VertexWorstRequiredPath) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); sta_->vertexWorstRequiredPath(v, MinMax::max()); // May be nullptr if no required; just check it doesn't crash } TEST_F(StaDesignTest, VertexWorstRequiredPathRf) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstRequiredPath(v, RiseFall::rise(), MinMax::max()); EXPECT_NE(path, nullptr); } // --- vertexPathIterator --- TEST_F(StaDesignTest, VertexPathIteratorRfPathAP) { Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); // vertexPathIterator removed; using vertexWorstArrivalPath instead Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); (void)path; } // --- checkSlewLimits --- TEST_F(StaDesignTest, CheckSlewLimitPreambleAndLimits) { ASSERT_NO_THROW(( [&](){ sta_->checkSlewsPreamble(); sta_->reportSlewChecks(nullptr, 10, false, false, sta_->scenes(), MinMax::max()); // May be empty; just check no crash }() )); } TEST_F(StaDesignTest, CheckSlewViolators) { ASSERT_NO_THROW(( [&](){ sta_->checkSlewsPreamble(); sta_->reportSlewChecks(nullptr, 10, false, false, sta_->scenes(), MinMax::max()); }() )); } // --- checkSlew (single pin) --- TEST_F(StaDesignTest, CheckSlew) { sta_->checkSlewsPreamble(); Pin *pin = findPin("u1/Z"); ASSERT_NE(pin, nullptr); const Scene *corner1 = nullptr; const RiseFall *tr = nullptr; Slew slew; float limit, slack; sta_->checkSlew(pin, sta_->scenes(), MinMax::max(), false, slew, limit, slack, tr, corner1); } // --- findSlewLimit --- TEST_F(StaDesignTest, FindSlewLimit) { sta_->checkSlewsPreamble(); LibertyCell *buf = lib_->findLibertyCell("BUF_X1"); ASSERT_NE(buf, nullptr); LibertyPort *port_z = buf->findLibertyPort("Z"); ASSERT_NE(port_z, nullptr); float limit = 0.0f; bool exists = false; sta_->findSlewLimit(port_z, sta_->cmdScene(), MinMax::max(), limit, exists); } // --- checkFanoutLimits --- TEST_F(StaDesignTest, CheckFanoutLimits) { ASSERT_NO_THROW(( [&](){ sta_->checkFanoutPreamble(); sta_->reportFanoutChecks(nullptr, 10, false, false, sta_->scenes(), MinMax::max()); }() )); } TEST_F(StaDesignTest, CheckFanoutViolators) { ASSERT_NO_THROW(( [&](){ sta_->checkFanoutPreamble(); sta_->reportFanoutChecks(nullptr, 10, false, false, sta_->scenes(), MinMax::max()); }() )); } // --- checkFanout (single pin) --- TEST_F(StaDesignTest, CheckFanout) { sta_->checkFanoutPreamble(); Pin *pin = findPin("u1/Z"); ASSERT_NE(pin, nullptr); float fanout, limit, slack; sta_->checkFanout(pin, sta_->cmdMode(), MinMax::max(), fanout, limit, slack); } // --- checkCapacitanceLimits --- TEST_F(StaDesignTest, CheckCapacitanceLimits) { ASSERT_NO_THROW(( [&](){ sta_->checkCapacitancesPreamble(sta_->scenes()); sta_->reportCapacitanceChecks(nullptr, 10, false, false, sta_->scenes(), MinMax::max()); }() )); } TEST_F(StaDesignTest, CheckCapacitanceViolators) { ASSERT_NO_THROW(( [&](){ sta_->checkCapacitancesPreamble(sta_->scenes()); sta_->reportCapacitanceChecks(nullptr, 10, false, false, sta_->scenes(), MinMax::max()); }() )); } // --- checkCapacitance (single pin) --- TEST_F(StaDesignTest, CheckCapacitance) { sta_->checkCapacitancesPreamble(sta_->scenes()); Pin *pin = findPin("u1/Z"); ASSERT_NE(pin, nullptr); const Scene *corner1 = nullptr; const RiseFall *tr = nullptr; float cap, limit, slack; sta_->checkCapacitance(pin, sta_->scenes(), MinMax::max(), cap, limit, slack, tr, corner1); } // --- minPulseWidthSlack --- TEST_F(StaDesignTest, MinPulseWidthSlack) { ASSERT_NO_THROW(( [&](){ sta_->reportMinPulseWidthChecks(nullptr, 10, false, false, sta_->scenes()); // May be nullptr; just don't crash }() )); } // --- minPulseWidthViolations --- TEST_F(StaDesignTest, MinPulseWidthViolations) { ASSERT_NO_THROW(( [&](){ sta_->reportMinPulseWidthChecks(nullptr, 10, true, false, sta_->scenes()); }() )); } // --- minPulseWidthChecks (all) --- TEST_F(StaDesignTest, MinPulseWidthChecksAll) { ASSERT_NO_THROW(( [&](){ sta_->reportMinPulseWidthChecks(nullptr, 10, false, false, sta_->scenes()); }() )); } // --- minPeriodSlack --- TEST_F(StaDesignTest, MinPeriodSlack) { ASSERT_NO_THROW(( [&](){ sta_->reportMinPeriodChecks(nullptr, 10, false, false, sta_->scenes()); }() )); } // --- minPeriodViolations --- TEST_F(StaDesignTest, MinPeriodViolations) { ASSERT_NO_THROW(( [&](){ sta_->reportMinPeriodChecks(nullptr, 10, true, false, sta_->scenes()); }() )); } // --- maxSkewSlack --- TEST_F(StaDesignTest, MaxSkewSlack) { ASSERT_NO_THROW(( [&](){ sta_->reportMaxSkewChecks(nullptr, 10, false, false, sta_->scenes()); }() )); } // --- maxSkewViolations --- TEST_F(StaDesignTest, MaxSkewViolations) { ASSERT_NO_THROW(( [&](){ sta_->reportMaxSkewChecks(nullptr, 10, true, false, sta_->scenes()); }() )); } // --- reportCheck (MaxSkewCheck) --- TEST_F(StaDesignTest, ReportCheckMaxSkew) { // maxSkewSlack/reportCheck removed; testing reportMaxSkewChecks instead sta_->reportMaxSkewChecks(nullptr, 10, false, false, sta_->scenes()); } // --- reportCheck (MinPeriodCheck) --- TEST_F(StaDesignTest, ReportCheckMinPeriod) { // minPeriodSlack/reportCheck removed; testing reportMinPeriodChecks instead sta_->reportMinPeriodChecks(nullptr, 10, false, false, sta_->scenes()); } // --- reportMpwCheck --- TEST_F(StaDesignTest, ReportMpwCheck) { // minPulseWidthSlack/reportMpwCheck removed; testing reportMinPulseWidthChecks instead sta_->reportMinPulseWidthChecks(nullptr, 10, false, false, sta_->scenes()); } // --- findPathEnds --- TEST_F(StaDesignTest, FindPathEnds) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, // group_path_count 1, // endpoint_path_count false, // unique_pins false, // unique_edges -INF, // slack_min INF, // slack_max false, // sort_by_slack group_names, // group_names (empty = all) true, // setup false, // hold false, // recovery false, // removal false, // clk_gating_setup false); // clk_gating_hold // Should find some path ends in this design }() )); } // --- reportPathEndHeader / Footer --- TEST_F(StaDesignTest, ReportPathEndHeaderFooter) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::full); }() )); } // --- reportPathEnd --- TEST_F(StaDesignTest, ReportPathEnd) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } // --- reportPathEnds --- TEST_F(StaDesignTest, ReportPathEnds) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); sta_->reportPathEnds(&ends); }() )); } // --- reportClkSkew --- TEST_F(StaDesignTest, ReportClkSkew) { Clock *clk = sta_->cmdSdc()->findClock("clk"); ASSERT_NE(clk, nullptr); ConstClockSeq clks; clks.push_back(clk); sta_->reportClkSkew(clks, sta_->scenes(), SetupHold::max(), false, 4); } // --- isClock(Net*) --- TEST_F(StaDesignTest, IsClockNet) { sta_->ensureClkNetwork(sta_->cmdMode()); Network *network = sta_->cmdNetwork(); Pin *clk1_pin = findPin("clk1"); ASSERT_NE(clk1_pin, nullptr); Net *clk_net = network->net(clk1_pin); if (clk_net) { bool is_clk = sta_->isClock(clk_net, sta_->cmdMode()); EXPECT_TRUE(is_clk); } } // --- pins(Clock*) --- TEST_F(StaDesignTest, ClockPins) { sta_->ensureClkNetwork(sta_->cmdMode()); Clock *clk = sta_->cmdSdc()->findClock("clk"); ASSERT_NE(clk, nullptr); const PinSet *pins = sta_->pins(clk, sta_->cmdMode()); EXPECT_NE(pins, nullptr); if (pins) { EXPECT_GT(pins->size(), 0u); } } // --- pvt / setPvt --- TEST_F(StaDesignTest, PvtGetSet) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); const Pvt *p = sta_->pvt(top, MinMax::max(), sta_->cmdSdc()); // p may be nullptr if not set; just don't crash sta_->setPvt(top, MinMaxAll::all(), 1.0f, 1.1f, 25.0f, sta_->cmdSdc()); p = sta_->pvt(top, MinMax::max(), sta_->cmdSdc()); (void)p; }() )); } // --- findDelays(int) --- TEST_F(StaDesignTest, FindDelaysLevel) { ASSERT_NO_THROW(( [&](){ sta_->findDelays(0); }() )); } // --- findDelays (no arg - public) --- TEST_F(StaDesignTest, FindDelays) { ASSERT_NO_THROW(( [&](){ sta_->findDelays(); }() )); } // --- arrivalsInvalid / delaysInvalid --- TEST_F(StaDesignTest, ArrivalsInvalid) { ASSERT_NO_THROW(( [&](){ sta_->arrivalsInvalid(); }() )); } TEST_F(StaDesignTest, DelaysInvalid) { ASSERT_NO_THROW(( [&](){ sta_->delaysInvalid(); }() )); } // --- makeEquivCells --- TEST_F(StaDesignTest, MakeEquivCells) { ASSERT_NO_THROW(( [&](){ LibertyLibrarySeq *equiv_libs = new LibertyLibrarySeq; equiv_libs->push_back(lib_); LibertyLibrarySeq *map_libs = new LibertyLibrarySeq; map_libs->push_back(lib_); sta_->makeEquivCells(equiv_libs, map_libs); // Check equivCells for BUF_X1 LibertyCell *buf = lib_->findLibertyCell("BUF_X1"); if (buf) { LibertyCellSeq *equiv = sta_->equivCells(buf); EXPECT_NE(equiv, nullptr); } }() )); } // --- maxPathCountVertex --- TEST_F(StaDesignTest, MaxPathCountVertex) { ASSERT_NO_THROW(( [&](){ sta_->maxPathCountVertex(); // May be nullptr; just don't crash }() )); } // --- makeParasiticAnalysisPts --- TEST_F(StaDesignTest, MakeParasiticAnalysisPts) { ASSERT_NO_THROW(( [&](){ // setParasiticAnalysisPts removed // Ensures parasitic analysis points are set up }() )); } // --- findLogicConstants (Sim) --- TEST_F(StaDesignTest, FindLogicConstants) { ASSERT_NO_THROW(( [&](){ sta_->findLogicConstants(); sta_->clearLogicConstants(); }() )); } // --- checkTiming --- TEST_F(StaDesignTest, CheckTiming) { ASSERT_NO_THROW(( [&](){ sta_->checkTiming( sta_->cmdMode(), true, // no_input_delay true, // no_output_delay true, // reg_multiple_clks true, // reg_no_clks true, // unconstrained_endpoints true, // loops true); // generated_clks }() )); } // --- Property methods --- TEST_F(StaDesignTest, PropertyGetPinArrival) { Properties &props = sta_->properties(); Pin *pin = findPin("u1/Z"); ASSERT_NE(pin, nullptr); props.getProperty(pin, "arrival_max_rise"); } TEST_F(StaDesignTest, PropertyGetPinSlack) { Properties &props = sta_->properties(); Pin *pin = findPin("r3/D"); ASSERT_NE(pin, nullptr); props.getProperty(pin, "slack_max"); } TEST_F(StaDesignTest, PropertyGetPinSlew) { Properties &props = sta_->properties(); Pin *pin = findPin("u1/Z"); ASSERT_NE(pin, nullptr); props.getProperty(pin, "slew_max"); } TEST_F(StaDesignTest, PropertyGetPinArrivalFall) { Properties &props = sta_->properties(); Pin *pin = findPin("u1/Z"); ASSERT_NE(pin, nullptr); props.getProperty(pin, "arrival_max_fall"); } TEST_F(StaDesignTest, PropertyGetInstanceName) { Properties &props = sta_->properties(); Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Instance *u1 = network->findChild(top, "u1"); ASSERT_NE(u1, nullptr); props.getProperty(u1, "full_name"); } TEST_F(StaDesignTest, PropertyGetNetName) { Properties &props = sta_->properties(); Network *network = sta_->cmdNetwork(); Pin *pin = findPin("u1/Z"); ASSERT_NE(pin, nullptr); Net *net = network->net(pin); if (net) { props.getProperty(net, "name"); } } // --- Search methods --- TEST_F(StaDesignTest, SearchCopyState) { Search *search = sta_->search(); ASSERT_NE(search, nullptr); search->copyState(sta_); } TEST_F(StaDesignTest, SearchFindPathGroupByName) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); (void)search; // First ensure path groups exist sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); // Search::findPathGroup removed }() )); } TEST_F(StaDesignTest, SearchFindPathGroupByClock) { Search *search = sta_->search(); (void)search; sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); Clock *clk = sta_->cmdSdc()->findClock("clk"); ASSERT_NE(clk, nullptr); // Search::findPathGroup removed } TEST_F(StaDesignTest, SearchReportTagGroups) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); search->reportTagGroups(); }() )); } TEST_F(StaDesignTest, SearchDeletePathGroups) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); // Ensure path groups exist first sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); search->deletePathGroups(); }() )); } TEST_F(StaDesignTest, SearchVisitEndpoints) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); (void)search; Network *network = sta_->cmdNetwork(); PinSet pins(network); VertexPinCollector collector(pins); (void)true /* Search::visitEndpoints removed */; }() )); } // --- Search: visitStartpoints --- TEST_F(StaDesignTest, SearchVisitStartpoints) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); (void)search; Network *network = sta_->cmdNetwork(); PinSet pins(network); VertexPinCollector collector(pins); (void)true /* Search::visitStartpoints removed */; }() )); } TEST_F(StaDesignTest, SearchTagGroup) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); // Tag group index 0 may or may not exist; just don't crash if (search->tagGroupCount() > 0) { TagGroup *tg = search->tagGroup(0); EXPECT_NE(tg, nullptr); } }() )); } TEST_F(StaDesignTest, SearchClockDomainsVertex) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); Vertex *v = findVertex("r1/CK"); if (v) { search->clockDomains(v, sta_->cmdMode()); } }() )); } TEST_F(StaDesignTest, SearchIsGenClkSrc) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); (void)search; Vertex *v = findVertex("r1/Q"); if (v) { (void)true /* Search::isGenClkSrc removed */; } }() )); } TEST_F(StaDesignTest, SearchPathGroups) { ASSERT_NO_THROW(( [&](){ // Get a path end to query its path groups PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (!ends.empty()) { Search *search = sta_->search(); (void)search; (void)true /* Search::pathGroups removed */; } }() )); } TEST_F(StaDesignTest, SearchPathClkPathArrival) { Search *search = sta_->search(); // Get a path from a vertex Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path && !path->isNull()) { search->pathClkPathArrival(path); } } // --- ReportPath methods --- // --- ReportPath: reportFull exercised through reportPathEnd (full format) --- TEST_F(StaDesignTest, ReportPathFullClockFormat) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::full_clock); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } TEST_F(StaDesignTest, ReportPathFullClockExpandedFormat) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::full_clock_expanded); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } TEST_F(StaDesignTest, ReportPathShorterFormat) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::shorter); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } TEST_F(StaDesignTest, ReportPathJsonFormat) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::json); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } TEST_F(StaDesignTest, ReportPathShortMpw) { // minPulseWidthSlack and reportShort(MinPulseWidthCheck) removed ReportPath *rpt = sta_->reportPath(); ASSERT_NE(rpt, nullptr); } TEST_F(StaDesignTest, ReportPathVerboseMpw) { // minPulseWidthSlack and reportVerbose(MinPulseWidthCheck) removed ReportPath *rpt = sta_->reportPath(); ASSERT_NE(rpt, nullptr); } // --- ReportPath: reportJson --- TEST_F(StaDesignTest, ReportJsonHeaderFooter) { ReportPath *rpt = sta_->reportPath(); ASSERT_NE(rpt, nullptr); rpt->reportJsonHeader(); rpt->reportJsonFooter(); } TEST_F(StaDesignTest, ReportJsonPathEnd) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (!ends.empty()) { ReportPath *rpt = sta_->reportPath(); rpt->reportJsonHeader(); rpt->reportJson(ends[0], ends.size() == 1); rpt->reportJsonFooter(); } }() )); } // --- disable / removeDisable --- TEST_F(StaDesignTest, DisableEnableLibertyPort) { LibertyCell *buf = lib_->findLibertyCell("BUF_X1"); ASSERT_NE(buf, nullptr); LibertyPort *port_a = buf->findLibertyPort("A"); ASSERT_NE(port_a, nullptr); sta_->disable(port_a, sta_->cmdSdc()); sta_->removeDisable(port_a, sta_->cmdSdc()); } TEST_F(StaDesignTest, DisableEnableTimingArcSet) { LibertyCell *buf = lib_->findLibertyCell("BUF_X1"); ASSERT_NE(buf, nullptr); const TimingArcSetSeq &arc_sets = buf->timingArcSets(); ASSERT_GT(arc_sets.size(), 0u); sta_->disable(arc_sets[0], sta_->cmdSdc()); sta_->removeDisable(arc_sets[0], sta_->cmdSdc()); } TEST_F(StaDesignTest, DisableEnableEdge) { Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); // Get an edge from this vertex VertexInEdgeIterator edge_iter(v, sta_->graph()); if (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); sta_->disable(edge, sta_->cmdSdc()); sta_->removeDisable(edge, sta_->cmdSdc()); } } // --- disableClockGatingCheck / removeDisableClockGatingCheck --- TEST_F(StaDesignTest, DisableClockGatingCheckPin) { Pin *pin = findPin("r1/CK"); ASSERT_NE(pin, nullptr); sta_->disableClockGatingCheck(pin, sta_->cmdSdc()); sta_->removeDisableClockGatingCheck(pin, sta_->cmdSdc()); } // --- setCmdNamespace1 (Sta internal) --- TEST_F(StaDesignTest, SetCmdNamespace1) { sta_->setCmdNamespace(CmdNamespace::sdc); EXPECT_EQ(sta_->cmdNamespace(), CmdNamespace::sdc); sta_->setCmdNamespace(CmdNamespace::sta); EXPECT_EQ(sta_->cmdNamespace(), CmdNamespace::sta); } // --- delaysInvalidFromFanin --- TEST_F(StaDesignTest, DelaysInvalidFromFaninPin) { Pin *pin = findPin("u1/Z"); ASSERT_NE(pin, nullptr); sta_->delaysInvalidFromFanin(pin); } // --- setArcDelayAnnotated --- TEST_F(StaDesignTest, SetArcDelayAnnotated) { Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); VertexInEdgeIterator edge_iter(v, sta_->graph()); if (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); TimingArcSet *arc_set = edge->timingArcSet(); if (arc_set) { const TimingArcSeq &arcs = arc_set->arcs(); if (!arcs.empty()) { Scene *corner = sta_->cmdScene(); DcalcAPIndex dcalc_idx = corner->dcalcAnalysisPtIndex(MinMax::max()); (void)dcalc_idx; sta_->setArcDelayAnnotated(edge, arcs[0], corner, MinMax::max(), true); sta_->setArcDelayAnnotated(edge, arcs[0], corner, MinMax::max(), false); } } } } // --- pathAnalysisPt / pathDcalcAnalysisPt --- TEST_F(StaDesignTest, PathAnalysisPt) { Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path && !path->isNull()) { size_t pa = path->tag(sta_)->scene()->index(); EXPECT_GE(pa, 0u); DcalcAPIndex da = path->tag(sta_)->scene()->dcalcAnalysisPtIndex(path->minMax(sta_)); EXPECT_GE(da, 0); } } // --- worstSlack / totalNegativeSlack --- TEST_F(StaDesignTest, WorstSlack) { ASSERT_NO_THROW(( [&](){ Slack worst; Vertex *worst_vertex = nullptr; sta_->worstSlack(MinMax::max(), worst, worst_vertex); }() )); } TEST_F(StaDesignTest, WorstSlackCorner) { ASSERT_NO_THROW(( [&](){ Slack worst; Vertex *worst_vertex = nullptr; Scene *corner = sta_->cmdScene(); sta_->worstSlack(corner, MinMax::max(), worst, worst_vertex); }() )); } TEST_F(StaDesignTest, TotalNegativeSlack) { ASSERT_NO_THROW(( [&](){ sta_->totalNegativeSlack(MinMax::max()); }() )); } TEST_F(StaDesignTest, TotalNegativeSlackCorner) { ASSERT_NO_THROW(( [&](){ Scene *corner = sta_->cmdScene(); sta_->totalNegativeSlack(corner, MinMax::max()); }() )); } // --- endpoints / endpointViolationCount --- TEST_F(StaDesignTest, Endpoints) { VertexSet &eps = sta_->endpoints(); (void)eps; // endpoints() returns reference, always valid } TEST_F(StaDesignTest, EndpointViolationCount) { ASSERT_NO_THROW(( [&](){ int count = sta_->endpointViolationCount(MinMax::max()); EXPECT_GE(count, 0); }() )); } // --- findRequireds --- TEST_F(StaDesignTest, FindRequireds) { ASSERT_NO_THROW(( [&](){ sta_->findRequireds(); }() )); } // --- Search: tag(0) --- TEST_F(StaDesignTest, SearchTag) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); if (search->tagCount() > 0) { Tag *t = search->tag(0); EXPECT_NE(t, nullptr); } }() )); } // --- Levelize: checkLevels --- TEST_F(StaDesignTest, GraphLoops) { ASSERT_NO_THROW(( [&](){ sta_->graphLoops(); }() )); } // --- reportPath (Path*) --- TEST_F(StaDesignTest, ReportPath) { Vertex *v = findVertex("u2/ZN"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path && !path->isNull()) { sta_->reportPath(path); } } // --- ClkNetwork: clocks(Pin*) --- TEST_F(StaDesignTest, ClkNetworkClocksPinDirect) { sta_->ensureClkNetwork(sta_->cmdMode()); ClkNetwork *clk_net = sta_->cmdMode()->clkNetwork(); ASSERT_NE(clk_net, nullptr); Pin *clk1_pin = findPin("clk1"); ASSERT_NE(clk1_pin, nullptr); const ClockSet *clks = clk_net->clocks(clk1_pin); EXPECT_NE(clks, nullptr); } // --- ClkNetwork: pins(Clock*) --- TEST_F(StaDesignTest, ClkNetworkPins) { sta_->ensureClkNetwork(sta_->cmdMode()); ClkNetwork *clk_net = sta_->cmdMode()->clkNetwork(); ASSERT_NE(clk_net, nullptr); Clock *clk = sta_->cmdSdc()->findClock("clk"); ASSERT_NE(clk, nullptr); const PinSet *pins = clk_net->pins(clk); EXPECT_NE(pins, nullptr); } // --- ClkNetwork: isClock(Net*) --- TEST_F(StaDesignTest, ClkNetworkIsClockNet) { sta_->ensureClkNetwork(sta_->cmdMode()); ClkNetwork *clk_net = sta_->cmdMode()->clkNetwork(); ASSERT_NE(clk_net, nullptr); Pin *clk1_pin = findPin("clk1"); ASSERT_NE(clk1_pin, nullptr); Network *network = sta_->cmdNetwork(); Net *net = network->net(clk1_pin); if (net) { clk_net->isClock(net); } } // --- ClkInfo accessors --- TEST_F(StaDesignTest, ClkInfoAccessors) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); if (search->tagCount() > 0) { Tag *tag = search->tag(0); if (tag) { const ClkInfo *clk_info = tag->clkInfo(); if (clk_info) { const ClockEdge *edge = clk_info->clkEdge(); EXPECT_NE(edge, nullptr); clk_info->isPropagated(); clk_info->isGenClkSrcPath(); } } } }() )); } // --- Tag accessors --- TEST_F(StaDesignTest, TagAccessors) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); if (search->tagCount() > 0) { Tag *tag = search->tag(0); if (tag) { PathAPIndex idx = tag->scene()->index(); EXPECT_GE(idx, 0); const Pin *src = tag->clkSrc(); EXPECT_NE(src, nullptr); } } }() )); } // --- TagGroup::report --- TEST_F(StaDesignTest, TagGroupReport) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); if (search->tagGroupCount() > 0) { TagGroup *tg = search->tagGroup(0); if (tg) { tg->report(sta_); } } }() )); } // --- BfsIterator --- TEST_F(StaDesignTest, BfsIteratorInit) { BfsFwdIterator *iter = sta_->search()->arrivalIterator(); ASSERT_NE(iter, nullptr); // Just verify the iterator exists - init is called internally } // --- SearchPred1 --- TEST_F(StaDesignTest, SearchPredNonReg2SearchThru) { SearchPred1 pred(sta_); Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); VertexInEdgeIterator edge_iter(v, sta_->graph()); if (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); pred.searchThru(edge); } } // --- PathExpanded --- TEST_F(StaDesignTest, PathExpanded) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path && !path->isNull()) { PathExpanded expanded(path, false, sta_); size_t size = expanded.size(); for (size_t i = 0; i < size; i++) { const Path *p = expanded.path(i); EXPECT_NE(p, nullptr); } } } // --- Search: endpoints --- TEST_F(StaDesignTest, SearchEndpoints) { Search *search = sta_->search(); VertexSet &eps = search->endpoints(); (void)eps; // endpoints() returns reference, always valid } // --- FindRegister (findRegs) --- TEST_F(StaDesignTest, FindRegPins) { Clock *clk = sta_->cmdSdc()->findClock("clk"); ASSERT_NE(clk, nullptr); ClockSet clk_set; clk_set.insert(clk); sta_->findRegisterClkPins(&clk_set, RiseFallBoth::riseFall(), false, false, sta_->cmdMode()); } TEST_F(StaDesignTest, FindRegDataPins) { ASSERT_NO_THROW(( [&](){ sta_->findRegisterDataPins(nullptr, RiseFallBoth::riseFall(), false, false, sta_->cmdMode()); }() )); } TEST_F(StaDesignTest, FindRegOutputPins) { ASSERT_NO_THROW(( [&](){ sta_->findRegisterOutputPins(nullptr, RiseFallBoth::riseFall(), false, false, sta_->cmdMode()); }() )); } TEST_F(StaDesignTest, FindRegAsyncPins) { ASSERT_NO_THROW(( [&](){ sta_->findRegisterAsyncPins(nullptr, RiseFallBoth::riseFall(), false, false, sta_->cmdMode()); }() )); } TEST_F(StaDesignTest, FindRegInstances) { ASSERT_NO_THROW(( [&](){ sta_->findRegisterInstances(nullptr, RiseFallBoth::riseFall(), false, false, sta_->cmdMode()); }() )); } // --- Sim::findLogicConstants --- TEST_F(StaDesignTest, SimFindLogicConstants) { // Sim access removed from Sta sta_->findLogicConstants(); } // --- reportSlewLimitShortHeader --- TEST_F(StaDesignTest, ReportSlewLimitShortHeader) { ASSERT_NO_THROW(( [&](){ // reportSlewLimitShortHeader removed; }() )); } // --- reportFanoutLimitShortHeader --- TEST_F(StaDesignTest, ReportFanoutLimitShortHeader) { ASSERT_NO_THROW(( [&](){ // reportFanoutLimitShortHeader removed; }() )); } // --- reportCapacitanceLimitShortHeader --- TEST_F(StaDesignTest, ReportCapacitanceLimitShortHeader) { ASSERT_NO_THROW(( [&](){ // reportCapacitanceLimitShortHeader removed; }() )); } // --- Path methods --- TEST_F(StaDesignTest, PathTransition) { Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path && !path->isNull()) { const RiseFall *rf = path->transition(sta_); EXPECT_NE(rf, nullptr); } } // --- endpointSlack --- TEST_F(StaDesignTest, EndpointSlack) { Pin *pin = findPin("r3/D"); ASSERT_NE(pin, nullptr); sta_->endpointSlack(pin, "clk", MinMax::max()); } // --- replaceCell --- TEST_F(StaDesignTest, ReplaceCell) { Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); // Find instance u1 (BUF_X1) Instance *u1 = network->findChild(top, "u1"); ASSERT_NE(u1, nullptr); // Replace with BUF_X2 (should exist in nangate45) LibertyCell *buf_x2 = lib_->findLibertyCell("BUF_X2"); if (buf_x2) { sta_->replaceCell(u1, buf_x2); // Replace back LibertyCell *buf_x1 = lib_->findLibertyCell("BUF_X1"); if (buf_x1) sta_->replaceCell(u1, buf_x1); } } // --- reportPathEnd with prev_end --- TEST_F(StaDesignTest, ReportPathEndWithPrev) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (ends.size() >= 2) { sta_->reportPathEnd(ends[1]); } }() )); } // --- PathEnd static methods --- TEST_F(StaDesignTest, PathEndLess) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (ends.size() >= 2) { PathEnd::less(ends[0], ends[1], true, sta_); PathEnd::cmpNoCrpr(ends[0], ends[1], sta_); } }() )); } // --- PathEnd accessors on real path ends --- TEST_F(StaDesignTest, PathEndAccessors) { PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (!ends.empty()) { PathEnd *end = ends[0]; const char *tn = end->typeName(); EXPECT_NE(tn, nullptr); end->type(); const RiseFall *rf = end->transition(sta_); EXPECT_NE(rf, nullptr); // PathEnd::pathIndex removed; use path->pathIndex instead PathAPIndex idx = end->path()->pathIndex(sta_); EXPECT_GE(idx, 0); const Clock *tgt_clk = end->targetClk(sta_); EXPECT_NE(tgt_clk, nullptr); end->targetClkArrival(sta_); end->targetClkTime(sta_); end->targetClkOffset(sta_); end->targetClkDelay(sta_); end->targetClkInsertionDelay(sta_); end->targetClkUncertainty(sta_); end->targetNonInterClkUncertainty(sta_); end->interClkUncertainty(sta_); end->targetClkMcpAdjustment(sta_); } } // --- ReportPath: reportShort for MinPeriodCheck --- TEST_F(StaDesignTest, ReportPathShortMinPeriod) { // minPeriodSlack and reportShort(MinPeriodCheck) removed ReportPath *rpt = sta_->reportPath(); ASSERT_NE(rpt, nullptr); } // --- ReportPath: reportShort for MaxSkewCheck --- TEST_F(StaDesignTest, ReportPathShortMaxSkew) { // maxSkewSlack and reportShort(MaxSkewCheck) removed ReportPath *rpt = sta_->reportPath(); ASSERT_NE(rpt, nullptr); } // --- ReportPath: reportCheck for MaxSkewCheck --- TEST_F(StaDesignTest, ReportPathCheckMaxSkew) { // maxSkewSlack and reportCheck(MaxSkewCheck) removed ReportPath *rpt = sta_->reportPath(); ASSERT_NE(rpt, nullptr); } // --- ReportPath: reportVerbose for MaxSkewCheck --- TEST_F(StaDesignTest, ReportPathVerboseMaxSkew) { // maxSkewSlack and reportVerbose(MaxSkewCheck) removed ReportPath *rpt = sta_->reportPath(); ASSERT_NE(rpt, nullptr); } // --- ReportPath: reportMpwChecks (covers mpwCheckHiLow internally) --- TEST_F(StaDesignTest, ReportMpwChecks) { // minPulseWidthChecks removed; testing reportMinPulseWidthChecks sta_->reportMinPulseWidthChecks(nullptr, 10, false, false, sta_->scenes()); } // --- findClkMinPeriod --- TEST_F(StaDesignTest, FindClkMinPeriod) { Clock *clk = sta_->cmdSdc()->findClock("clk"); ASSERT_NE(clk, nullptr); sta_->findClkMinPeriod(clk, false); } // --- slowDrivers --- TEST_F(StaDesignTest, SlowDrivers) { ASSERT_NO_THROW(( [&](){ sta_->slowDrivers(5); }() )); } // --- vertexLevel --- TEST_F(StaDesignTest, VertexLevel) { Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); Level lvl = sta_->vertexLevel(v); EXPECT_GE(lvl, 0); } // --- simLogicValue --- TEST_F(StaDesignTest, SimLogicValue) { Pin *pin = findPin("u1/Z"); ASSERT_NE(pin, nullptr); sta_->simLogicValue(pin, sta_->cmdMode()); } // --- Search: clear (exercises initVars internally) --- TEST_F(StaDesignTest, SearchClear) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); // clear() calls initVars() internally search->clear(); }() )); } // --- readLibertyFile (protected, call through public readLiberty) --- // This tests readLibertyFile indirectly TEST_F(StaDesignTest, ReadLibertyFile) { ASSERT_NO_THROW(( [&](){ Scene *corner = sta_->cmdScene(); LibertyLibrary *lib = sta_->readLiberty( "test/nangate45/Nangate45_slow.lib", corner, MinMaxAll::min(), false); (void)lib; // May or may not succeed depending on file existence; just check no crash }() )); } // --- Property: getProperty on LibertyLibrary --- TEST_F(StaDesignTest, PropertyGetPropertyLibertyLibrary) { Properties &props = sta_->properties(); ASSERT_NE(lib_, nullptr); props.getProperty(lib_, "name"); } // --- Property: getProperty on LibertyCell --- TEST_F(StaDesignTest, PropertyGetPropertyLibertyCell) { Properties &props = sta_->properties(); LibertyCell *buf = lib_->findLibertyCell("BUF_X1"); ASSERT_NE(buf, nullptr); props.getProperty(buf, "name"); } // --- findPathEnds with unconstrained --- TEST_F(StaDesignTest, FindPathEndsUnconstrained) { ASSERT_NO_THROW(( [&](){ sta_->findPathEnds( nullptr, nullptr, nullptr, true, // unconstrained sta_->scenes(), // all scenes MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); }() )); } // --- findPathEnds with hold --- TEST_F(StaDesignTest, FindPathEndsHold) { ASSERT_NO_THROW(( [&](){ sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::min(), 10, 1, false, false, -INF, INF, false, group_names, false, true, false, false, false, false); }() )); } // --- Search: findAllArrivals --- TEST_F(StaDesignTest, SearchFindAllArrivals) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); search->findAllArrivals(); }() )); } // --- Search: findArrivals / findRequireds --- TEST_F(StaDesignTest, SearchFindArrivalsRequireds) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); search->findArrivals(); search->findRequireds(); }() )); } // --- Search: clocks for vertex --- TEST_F(StaDesignTest, SearchClocksVertex) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); Vertex *v = findVertex("r1/CK"); if (v) { search->clocks(v, sta_->cmdMode()); } }() )); } // --- Search: wnsSlack --- TEST_F(StaDesignTest, SearchWnsSlack) { Search *search = sta_->search(); Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); search->wnsSlack(v, 0); } // --- Search: isEndpoint --- TEST_F(StaDesignTest, SearchIsEndpoint) { Search *search = sta_->search(); Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); EXPECT_TRUE(search->isEndpoint(v)); } // --- reportParasiticAnnotation --- TEST_F(StaDesignTest, ReportParasiticAnnotation) { ASSERT_NO_THROW(( [&](){ sta_->reportParasiticAnnotation("", false); }() )); } // --- findClkDelays --- TEST_F(StaDesignTest, FindClkDelays) { Clock *clk = sta_->cmdSdc()->findClock("clk"); ASSERT_NE(clk, nullptr); sta_->findClkDelays(clk, sta_->cmdScene(), false); } // --- reportClkLatency --- TEST_F(StaDesignTest, ReportClkLatency) { Clock *clk = sta_->cmdSdc()->findClock("clk"); ASSERT_NE(clk, nullptr); ConstClockSeq clks; clks.push_back(clk); sta_->reportClkLatency(clks, sta_->scenes(), false, 4); } // --- findWorstClkSkew --- TEST_F(StaDesignTest, FindWorstClkSkew) { ASSERT_NO_THROW(( [&](){ sta_->findWorstClkSkew(SetupHold::max(), false); }() )); } // --- ReportPath: reportJson on a Path --- TEST_F(StaDesignTest, ReportJsonPath) { Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path && !path->isNull()) { ReportPath *rpt = sta_->reportPath(); rpt->reportJson(path); } } // --- reportEndHeader / reportEndLine --- TEST_F(StaDesignTest, ReportEndHeaderLine) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::endpoint); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); ReportPath *rpt = sta_->reportPath(); rpt->reportEndHeader(); if (!ends.empty()) { rpt->reportEndLine(ends[0]); } }() )); } // --- reportSummaryHeader / reportSummaryLine --- TEST_F(StaDesignTest, ReportSummaryHeaderLine) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::summary); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); ReportPath *rpt = sta_->reportPath(); rpt->reportSummaryHeader(); if (!ends.empty()) { rpt->reportSummaryLine(ends[0]); } }() )); } // --- reportSlackOnlyHeader / reportSlackOnly --- TEST_F(StaDesignTest, ReportSlackOnly) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::slack_only); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); ReportPath *rpt = sta_->reportPath(); rpt->reportSlackOnlyHeader(); if (!ends.empty()) { rpt->reportSlackOnly(ends[0]); } }() )); } // --- Search: reportArrivals --- TEST_F(StaDesignTest, SearchReportArrivals) { Search *search = sta_->search(); Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); search->reportArrivals(v, false); } // --- Search: reportPathCountHistogram --- TEST_F(StaDesignTest, SearchReportPathCountHistogram) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); search->reportPathCountHistogram(); }() )); } // --- Search: reportTags --- TEST_F(StaDesignTest, SearchReportTags) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); search->reportTags(); }() )); } // --- Search: reportClkInfos --- TEST_F(StaDesignTest, SearchReportClkInfos) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); search->reportClkInfos(); }() )); } // --- setReportPathFields --- TEST_F(StaDesignTest, SetReportPathFields) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFields(true, true, true, true, true, true, true, true); }() )); } // --- setReportPathFieldOrder --- TEST_F(StaDesignTest, SetReportPathFieldOrder) { ASSERT_NO_THROW(( [&](){ StringSeq fields; fields.push_back("Fanout"); fields.push_back("Cap"); sta_->setReportPathFieldOrder(fields); }() )); } // --- Search: saveEnumPath --- // (This is complex - need a valid enumerated path. Test existence.) TEST_F(StaDesignTest, SearchSaveEnumPathExists) { auto fn = &Search::saveEnumPath; expectCallablePointerUsable(fn); } // --- vertexPathCount --- TEST_F(StaDesignTest, VertexPathCount) { Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); int count = sta_->vertexPathCount(v); EXPECT_GE(count, 0); } // --- pathCount --- TEST_F(StaDesignTest, PathCount) { int count = sta_->pathCount(); EXPECT_GE(count, 0); } // --- writeSdc --- TEST_F(StaDesignTest, WriteSdc) { ASSERT_NO_THROW(( [&](){ sta_->writeSdc(sta_->cmdSdc(), "/dev/null", false, false, 4, false, true); }() )); } // --- ReportPath: reportFull for PathEndCheck --- TEST_F(StaDesignTest, ReportPathFullPathEnd) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::full); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (!ends.empty()) { // reportPathEnd with full format calls reportFull sta_->reportPathEnd(ends[0]); } }() )); } // --- Search: ensureDownstreamClkPins --- TEST_F(StaDesignTest, SearchEnsureDownstreamClkPins) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); search->ensureDownstreamClkPins(); }() )); } // --- Genclks --- TEST_F(StaDesignTest, GenclksAccessor) { // Search::genclks() removed from API Search *search = sta_->search(); EXPECT_NE(search, nullptr); } // --- CheckCrpr accessor --- TEST_F(StaDesignTest, CheckCrprAccessor) { Search *search = sta_->search(); CheckCrpr *crpr = search->checkCrpr(); EXPECT_NE(crpr, nullptr); } // --- GatedClk accessor --- TEST_F(StaDesignTest, GatedClkAccessor) { Search *search = sta_->search(); GatedClk *gated = search->gatedClk(); EXPECT_NE(gated, nullptr); } // --- VisitPathEnds accessor --- TEST_F(StaDesignTest, VisitPathEndsAccessor) { Search *search = sta_->search(); VisitPathEnds *vpe = search->visitPathEnds(); EXPECT_NE(vpe, nullptr); } // ============================================================ // Additional R8_ tests for more coverage // ============================================================ // --- Search: worstSlack (triggers WorstSlack methods) --- TEST_F(StaDesignTest, SearchWorstSlackMinMax) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); Slack worst; Vertex *worst_vertex = nullptr; search->worstSlack(MinMax::max(), worst, worst_vertex); }() )); } TEST_F(StaDesignTest, SearchWorstSlackCorner) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); Scene *corner = sta_->cmdScene(); Slack worst; Vertex *worst_vertex = nullptr; search->worstSlack(corner, MinMax::max(), worst, worst_vertex); }() )); } // --- Search: totalNegativeSlack --- TEST_F(StaDesignTest, SearchTotalNegativeSlack) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); search->totalNegativeSlack(MinMax::max()); }() )); } TEST_F(StaDesignTest, SearchTotalNegativeSlackCorner) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); Scene *corner = sta_->cmdScene(); search->totalNegativeSlack(corner, MinMax::max()); }() )); } // --- Property: getProperty on Edge --- TEST_F(StaDesignTest, PropertyGetEdge) { Properties &props = sta_->properties(); Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); VertexInEdgeIterator edge_iter(v, sta_->graph()); if (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); props.getProperty(edge, "full_name"); } } // --- Property: getProperty on Clock --- TEST_F(StaDesignTest, PropertyGetClock) { Properties &props = sta_->properties(); Clock *clk = sta_->cmdSdc()->findClock("clk"); ASSERT_NE(clk, nullptr); props.getProperty(clk, "name"); } // --- Property: getProperty on LibertyPort --- TEST_F(StaDesignTest, PropertyGetLibertyPort) { Properties &props = sta_->properties(); LibertyCell *buf = lib_->findLibertyCell("BUF_X1"); ASSERT_NE(buf, nullptr); LibertyPort *port = buf->findLibertyPort("A"); ASSERT_NE(port, nullptr); props.getProperty(port, "name"); } // --- Property: getProperty on Port --- TEST_F(StaDesignTest, PropertyGetPort) { Properties &props = sta_->properties(); Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Cell *cell = network->cell(top); ASSERT_NE(cell, nullptr); Port *port = network->findPort(cell, "clk1"); if (port) { props.getProperty(port, "name"); } } // --- Sta: makeInstance / deleteInstance --- TEST_F(StaDesignTest, MakeDeleteInstance) { LibertyCell *buf = lib_->findLibertyCell("BUF_X1"); ASSERT_NE(buf, nullptr); Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Instance *new_inst = sta_->makeInstance("test_buf", buf, top); ASSERT_NE(new_inst, nullptr); sta_->deleteInstance(new_inst); } // --- Sta: makeNet / deleteNet --- TEST_F(StaDesignTest, MakeDeleteNet) { Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Net *new_net = sta_->makeNet("test_net", top); ASSERT_NE(new_net, nullptr); sta_->deleteNet(new_net); } // --- Sta: connectPin / disconnectPin --- TEST_F(StaDesignTest, ConnectDisconnectPin) { LibertyCell *buf = lib_->findLibertyCell("BUF_X1"); ASSERT_NE(buf, nullptr); LibertyPort *port_a = buf->findLibertyPort("A"); ASSERT_NE(port_a, nullptr); Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Instance *new_inst = sta_->makeInstance("test_buf2", buf, top); ASSERT_NE(new_inst, nullptr); Net *new_net = sta_->makeNet("test_net2", top); ASSERT_NE(new_net, nullptr); sta_->connectPin(new_inst, port_a, new_net); // Find the pin and disconnect Pin *pin = network->findPin(new_inst, "A"); ASSERT_NE(pin, nullptr); sta_->disconnectPin(pin); sta_->deleteNet(new_net); sta_->deleteInstance(new_inst); } // --- Sta: endpointPins --- TEST_F(StaDesignTest, EndpointPins) { PinSet eps = sta_->endpointPins(); EXPECT_GT(eps.size(), 0u); } // --- Sta: startpointPins --- TEST_F(StaDesignTest, StartpointPins) { // startpointPins() is declared in Sta.hh but not defined - skip // PinSet sps = sta_->startpointPins(); // EXPECT_GT(sps.size(), 0u); } // --- Search: arrivalsValid --- TEST_F(StaDesignTest, SearchArrivalsValidDesign) { Search *search = sta_->search(); bool valid = search->arrivalsValid(); EXPECT_TRUE(valid); } // --- Sta: netSlack --- TEST_F(StaDesignTest, NetSlack) { Network *network = sta_->cmdNetwork(); Pin *pin = findPin("u1/Z"); ASSERT_NE(pin, nullptr); Net *net = network->net(pin); if (net) { sta_->slack(net, MinMax::max()); } } // --- Sta: pinSlack --- TEST_F(StaDesignTest, PinSlackMinMax) { Pin *pin = findPin("r3/D"); ASSERT_NE(pin, nullptr); sta_->slack(pin, RiseFallBoth::riseFall(), sta_->scenes(), MinMax::max()); } TEST_F(StaDesignTest, PinSlackRfMinMax) { Pin *pin = findPin("r3/D"); ASSERT_NE(pin, nullptr); sta_->slack(pin, RiseFallBoth::rise(), sta_->scenes(), MinMax::max()); } // --- Sta: pinArrival --- TEST_F(StaDesignTest, PinArrival) { Pin *pin = findPin("u1/Z"); ASSERT_NE(pin, nullptr); sta_->arrival(pin, RiseFallBoth::rise(), MinMax::max()); } // --- Sta: clocks / clockDomains --- TEST_F(StaDesignTest, ClocksOnPin) { Pin *pin = findPin("clk1"); ASSERT_NE(pin, nullptr); sta_->clocks(pin, sta_->cmdMode()); } TEST_F(StaDesignTest, ClockDomainsOnPin) { Pin *pin = findPin("r1/CK"); ASSERT_NE(pin, nullptr); sta_->clockDomains(pin, sta_->cmdMode()); } // --- Sta: vertexWorstArrivalPath (both overloads) --- TEST_F(StaDesignTest, VertexWorstArrivalPathMinMax) { Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); EXPECT_NE(path, nullptr); } TEST_F(StaDesignTest, VertexWorstArrivalPathRf) { Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, RiseFall::rise(), MinMax::max()); EXPECT_NE(path, nullptr); } // --- Sta: vertexWorstSlackPath --- TEST_F(StaDesignTest, VertexWorstSlackPath) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstSlackPath(v, MinMax::max()); EXPECT_NE(path, nullptr); } TEST_F(StaDesignTest, VertexWorstSlackPathRf) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstSlackPath(v, RiseFall::rise(), MinMax::max()); EXPECT_NE(path, nullptr); } // --- Search: isClock on clock vertex --- TEST_F(StaDesignTest, SearchIsClockVertex) { Search *search = sta_->search(); Vertex *v = findVertex("r1/CK"); ASSERT_NE(v, nullptr); (void)(search->clocks(v, sta_->cmdMode()).size() > 0); } // --- Search: clkPathArrival --- TEST_F(StaDesignTest, SearchClkPathArrival) { Search *search = sta_->search(); // Need a clock path Vertex *v = findVertex("r1/CK"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path && !path->isNull()) { search->clkPathArrival(path); } } // --- Sta: removeDelaySlewAnnotations --- TEST_F(StaDesignTest, RemoveDelaySlewAnnotations) { ASSERT_NO_THROW(( [&](){ sta_->removeDelaySlewAnnotations(); }() )); } // --- Sta: deleteParasitics --- TEST_F(StaDesignTest, DeleteParasitics) { ASSERT_NO_THROW(( [&](){ sta_->deleteParasitics(); }() )); } // --- Sta: delaysInvalid (constraintsChanged was removed) --- TEST_F(StaDesignTest, DelaysInvalid2) { ASSERT_NO_THROW(( [&](){ sta_->delaysInvalid(); }() )); } // --- Sta: networkChanged --- TEST_F(StaDesignTest, NetworkChanged) { ASSERT_NO_THROW(( [&](){ sta_->networkChanged(); }() )); } // --- Search: endpointsInvalid --- TEST_F(StaDesignTest, EndpointsInvalid) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); search->endpointsInvalid(); }() )); } // --- Search: requiredsInvalid --- TEST_F(StaDesignTest, RequiredsInvalid) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); search->requiredsInvalid(); }() )); } // --- Search: deleteFilter / filteredEndpoints --- TEST_F(StaDesignTest, SearchDeleteFilter) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); // No filter set, but calling is safe search->deleteFilter(); }() )); } // --- Sta: reportDelayCalc --- TEST_F(StaDesignTest, ReportDelayCalc) { Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); VertexInEdgeIterator edge_iter(v, sta_->graph()); if (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); TimingArcSet *arc_set = edge->timingArcSet(); if (arc_set && !arc_set->arcs().empty()) { Scene *corner = sta_->cmdScene(); sta_->reportDelayCalc( edge, arc_set->arcs()[0], corner, MinMax::max(), 4); } } } // --- Sta: arcDelay --- TEST_F(StaDesignTest, ArcDelay) { Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); VertexInEdgeIterator edge_iter(v, sta_->graph()); if (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); TimingArcSet *arc_set = edge->timingArcSet(); if (arc_set && !arc_set->arcs().empty()) { Scene *corner = sta_->cmdScene(); const DcalcAPIndex dcalc_idx = corner->dcalcAnalysisPtIndex(MinMax::max()); sta_->arcDelay(edge, arc_set->arcs()[0], dcalc_idx); } } } // --- Sta: arcDelayAnnotated --- TEST_F(StaDesignTest, ArcDelayAnnotated) { Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); VertexInEdgeIterator edge_iter(v, sta_->graph()); if (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); TimingArcSet *arc_set = edge->timingArcSet(); if (arc_set && !arc_set->arcs().empty()) { Scene *corner = sta_->cmdScene(); DcalcAPIndex dcalc_idx = corner->dcalcAnalysisPtIndex(MinMax::max()); (void)dcalc_idx; sta_->arcDelayAnnotated(edge, arc_set->arcs()[0], corner, MinMax::max()); } } } // --- Sta: findReportPathField --- TEST_F(StaDesignTest, FindReportPathField) { ASSERT_NO_THROW(( [&](){ sta_->findReportPathField("Fanout"); }() )); } // --- Search: arrivalInvalid on a vertex --- TEST_F(StaDesignTest, SearchArrivalInvalid) { Search *search = sta_->search(); Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); search->arrivalInvalid(v); } // --- Search: requiredInvalid on a vertex --- TEST_F(StaDesignTest, SearchRequiredInvalid) { Search *search = sta_->search(); Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); search->requiredInvalid(v); } // --- Search: isSegmentStart --- TEST_F(StaDesignTest, SearchIsSegmentStart) { Search *search = sta_->search(); (void)search; Pin *pin = findPin("in1"); ASSERT_NE(pin, nullptr); (void)true /* Search::isSegmentStart removed */; } // --- Search: isInputArrivalSrchStart --- TEST_F(StaDesignTest, SearchIsInputArrivalSrchStart) { Search *search = sta_->search(); Vertex *v = findVertex("in1"); ASSERT_NE(v, nullptr); EXPECT_TRUE(search->isInputArrivalSrchStart(v)); } // --- Sta: operatingConditions --- TEST_F(StaDesignTest, OperatingConditions) { ASSERT_NO_THROW(( [&](){ sta_->operatingConditions(MinMax::max(), sta_->cmdSdc()); }() )); } // --- Search: evalPred / searchAdj --- TEST_F(StaDesignTest, SearchEvalPred) { Search *search = sta_->search(); EvalPred *ep = search->evalPred(); EXPECT_NE(ep, nullptr); } TEST_F(StaDesignTest, SearchSearchAdj) { Search *search = sta_->search(); SearchPred *sp = search->searchAdj(); EXPECT_NE(sp, nullptr); } // --- Search: endpointInvalid --- TEST_F(StaDesignTest, SearchEndpointInvalid) { Search *search = sta_->search(); Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); search->endpointInvalid(v); } // --- Search: tnsInvalid --- TEST_F(StaDesignTest, SearchTnsInvalid) { Search *search = sta_->search(); Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); search->tnsInvalid(v); } // --- Sta: unsetTimingDerate --- TEST_F(StaDesignTest, UnsetTimingDerate) { ASSERT_NO_THROW(( [&](){ sta_->unsetTimingDerate(sta_->cmdSdc()); }() )); } // --- Sta: setAnnotatedSlew --- TEST_F(StaDesignTest, SetAnnotatedSlew) { Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); Scene *corner = sta_->cmdScene(); sta_->setAnnotatedSlew(v, corner, MinMaxAll::all(), RiseFallBoth::riseFall(), 1.0e-10f); } // --- Sta: vertexPathIterator with MinMax --- TEST_F(StaDesignTest, VertexPathIteratorMinMax) { Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); // vertexWorstArrivalPath returns a single Path* (not an iterator) Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); // May be null if no arrivals computed if (path) { EXPECT_FALSE(path->isNull()); } } // --- Tag comparison operations (exercised through timing) --- TEST_F(StaDesignTest, TagOperations) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); TagIndex count = search->tagCount(); if (count >= 2) { Tag *t0 = search->tag(0); Tag *t1 = search->tag(1); if (t0 && t1) { // Exercise TagLess TagLess less(sta_); less(t0, t1); // Exercise TagIndexLess TagIndexLess idx_less; idx_less(t0, t1); // Exercise Tag::equal Tag::equal(t0, t1, sta_); } } }() )); } // --- PathEnd::cmp --- TEST_F(StaDesignTest, PathEndCmp) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (ends.size() >= 2) { PathEnd::cmp(ends[0], ends[1], true, sta_); PathEnd::cmpSlack(ends[0], ends[1], sta_); PathEnd::cmpArrival(ends[0], ends[1], sta_); } }() )); } // --- PathEnd: various accessors on specific PathEnd types --- TEST_F(StaDesignTest, PathEndSlackNoCrpr) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (!ends.empty()) { PathEnd *end = ends[0]; end->slack(sta_); end->slackNoCrpr(sta_); end->margin(sta_); end->requiredTime(sta_); end->dataArrivalTime(sta_); end->sourceClkOffset(sta_); const ClockEdge *src_edge = end->sourceClkEdge(sta_); EXPECT_NE(src_edge, nullptr); end->sourceClkLatency(sta_); } }() )); } // --- PathEnd: reportShort --- TEST_F(StaDesignTest, PathEndReportShort) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (!ends.empty()) { ReportPath *rpt = sta_->reportPath(); ends[0]->reportShort(rpt); } }() )); } // --- PathEnd: copy --- TEST_F(StaDesignTest, PathEndCopy) { PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (!ends.empty()) { PathEnd *copy = ends[0]->copy(); EXPECT_NE(copy, nullptr); delete copy; } } // --- Search: tagGroup for a vertex --- TEST_F(StaDesignTest, SearchTagGroupForVertex) { Search *search = sta_->search(); Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); TagGroup *tg = search->tagGroup(v); EXPECT_NE(tg, nullptr); } // --- Sta: findFaninPins / findFanoutPins --- TEST_F(StaDesignTest, FindFaninPins) { Pin *pin = findPin("r3/D"); ASSERT_NE(pin, nullptr); PinSeq to_pins; to_pins.push_back(pin); sta_->findFaninPins(&to_pins, false, false, 0, 10, false, false, sta_->cmdMode()); } TEST_F(StaDesignTest, FindFanoutPins) { Pin *pin = findPin("r1/Q"); ASSERT_NE(pin, nullptr); PinSeq from_pins; from_pins.push_back(pin); sta_->findFanoutPins(&from_pins, false, false, 0, 10, false, false, sta_->cmdMode()); } // --- Sta: findFaninInstances / findFanoutInstances --- TEST_F(StaDesignTest, FindFaninInstances) { Pin *pin = findPin("r3/D"); ASSERT_NE(pin, nullptr); PinSeq to_pins; to_pins.push_back(pin); sta_->findFaninInstances(&to_pins, false, false, 0, 10, false, false, sta_->cmdMode()); } // --- Sta: setVoltage --- TEST_F(StaDesignTest, SetVoltage) { ASSERT_NO_THROW(( [&](){ sta_->setVoltage(MinMax::max(), 1.1f, sta_->cmdSdc()); }() )); } // --- Sta: removeConstraints --- TEST_F(StaDesignTest, RemoveConstraints) { ASSERT_NO_THROW(( [&](){ // This is a destructive operation, so call it but re-create constraints after // Just verifying it doesn't crash // removeConstraints() removed }() )); } // --- Search: filter --- TEST_F(StaDesignTest, SearchFilter) { Search *search = sta_->search(); (void)search; FilterPath *filter = nullptr /* Search::filter() removed */; // filter should be null since we haven't set one EXPECT_EQ(filter, nullptr); } // --- PathExpanded: path(i) and pathsIndex --- TEST_F(StaDesignTest, PathExpandedPaths) { Vertex *v = findVertex("u2/ZN"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path && !path->isNull()) { PathExpanded expanded(path, true, sta_); for (size_t i = 0; i < expanded.size(); i++) { const Path *p = expanded.path(i); EXPECT_NE(p, nullptr); } } } // --- Sta: setOutputDelay --- TEST_F(StaDesignTest, SetOutputDelay) { Pin *out = findPin("out"); ASSERT_NE(out, nullptr); Clock *clk = sta_->cmdSdc()->findClock("clk"); ASSERT_NE(clk, nullptr); sta_->setOutputDelay(out, RiseFallBoth::riseFall(), clk, RiseFall::rise(), nullptr, false, false, MinMaxAll::all(), true, 0.0f, sta_->cmdSdc()); } // --- Sta: findPathEnds with setup+hold --- TEST_F(StaDesignTest, FindPathEndsSetupHold) { ASSERT_NO_THROW(( [&](){ sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::all(), 10, 1, false, false, -INF, INF, false, group_names, true, true, false, false, false, false); }() )); } // --- Sta: findPathEnds unique_pins --- TEST_F(StaDesignTest, FindPathEndsUniquePins) { ASSERT_NO_THROW(( [&](){ sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 3, true, false, -INF, INF, false, group_names, true, false, false, false, false, false); }() )); } // --- Sta: findPathEnds sort_by_slack --- TEST_F(StaDesignTest, FindPathEndsSortBySlack) { ASSERT_NO_THROW(( [&](){ sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, true, group_names, true, false, false, false, false, false); }() )); } // --- Sta: reportChecks for MinPeriod --- TEST_F(StaDesignTest, ReportChecksMinPeriod) { // minPeriodViolations removed; test reportMinPeriodChecks sta_->reportMinPeriodChecks(nullptr, 10, false, false, sta_->scenes()); } // --- Sta: reportChecks for MaxSkew --- TEST_F(StaDesignTest, ReportChecksMaxSkew) { // maxSkewViolations removed; testing reportMaxSkewChecks sta_->reportMaxSkewChecks(nullptr, 10, false, false, sta_->scenes()); } // --- ReportPath: reportPeriodHeaderShort --- TEST_F(StaDesignTest, ReportPeriodHeaderShort) { ASSERT_NO_THROW(( [&](){ ReportPath *rpt = sta_->reportPath(); rpt->reportPeriodHeaderShort(); }() )); } // --- ReportPath: reportMpwHeaderShort --- TEST_F(StaDesignTest, ReportMpwHeaderShort) { ASSERT_NO_THROW(( [&](){ ReportPath *rpt = sta_->reportPath(); rpt->reportMpwHeaderShort(); }() )); } // --- Sta: maxSlewCheck --- TEST_F(StaDesignTest, MaxSlewCheck) { ASSERT_NO_THROW(( [&](){ sta_->checkSlewsPreamble(); const Pin *pin = nullptr; Slew slew; float slack, limit; sta_->maxSlewCheck(pin, slew, slack, limit); // pin may be null if no slew limits }() )); } // --- Sta: maxFanoutCheck --- TEST_F(StaDesignTest, MaxFanoutCheck) { ASSERT_NO_THROW(( [&](){ sta_->checkFanoutPreamble(); const Pin *pin = nullptr; (void)pin; float fanout, slack, limit; (void)fanout; (void)slack; (void)limit; // maxFanoutCheck removed (renamed to maxFanoutMinSlackPin); }() )); } // --- Sta: maxCapacitanceCheck --- TEST_F(StaDesignTest, MaxCapacitanceCheck) { ASSERT_NO_THROW(( [&](){ sta_->checkCapacitancesPreamble(sta_->scenes()); const Pin *pin = nullptr; float cap, slack, limit; sta_->maxCapacitanceCheck(pin, cap, slack, limit); }() )); } // --- Sta: vertexSlack with RiseFall + MinMax --- TEST_F(StaDesignTest, VertexSlackRfMinMax) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); sta_->slack(v, RiseFall::rise(), MinMax::max()); } // --- Sta: vertexSlew with MinMax only --- TEST_F(StaDesignTest, VertexSlewMinMax) { Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); sta_->slew(v, RiseFallBoth::riseFall(), sta_->scenes(), MinMax::max()); } // --- Sta: setReportPathFormat to each format and report --- TEST_F(StaDesignTest, ReportPathEndpointFormat) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::endpoint); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (ends.size() >= 2) { sta_->reportPathEnd(ends[0]); sta_->reportPathEnd(ends[1]); } }() )); } // --- Search: findClkVertexPins --- TEST_F(StaDesignTest, SearchFindClkVertexPins) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); PinSet clk_pins(sta_->cmdNetwork()); search->findClkVertexPins(clk_pins); }() )); } // --- Property: getProperty on PathEnd --- TEST_F(StaDesignTest, PropertyGetPathEnd) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (!ends.empty()) { Properties &props = sta_->properties(); props.getProperty(ends[0], "slack"); } }() )); } // --- Property: getProperty on Path --- TEST_F(StaDesignTest, PropertyGetPath) { Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path && !path->isNull()) { Properties &props = sta_->properties(); props.getProperty(path, "arrival"); } } // --- Property: getProperty on TimingArcSet --- TEST_F(StaDesignTest, PropertyGetTimingArcSet) { Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); VertexInEdgeIterator edge_iter(v, sta_->graph()); if (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); TimingArcSet *arc_set = edge->timingArcSet(); if (arc_set) { Properties &props = sta_->properties(); try { props.getProperty(arc_set, "from_pin"); } catch (...) {} } } } // --- Sta: setParasiticAnalysisPts per_corner --- TEST_F(StaDesignTest, SetParasiticAnalysisPtsPerCorner) { ASSERT_NO_THROW(( [&](){ // setParasiticAnalysisPts removed }() )); } // ============================================================ // R9_ tests: Comprehensive coverage for search module // ============================================================ // --- FindRegister tests --- TEST_F(StaDesignTest, FindRegisterInstances) { ClockSet *clks = nullptr; InstanceSet reg_insts = sta_->findRegisterInstances(clks, RiseFallBoth::riseFall(), true, false, sta_->cmdMode()); // Design has 3 DFF_X1 instances EXPECT_GE(reg_insts.size(), 1u); } TEST_F(StaDesignTest, FindRegisterDataPins) { ClockSet *clks = nullptr; PinSet data_pins = sta_->findRegisterDataPins(clks, RiseFallBoth::riseFall(), true, false, sta_->cmdMode()); EXPECT_GE(data_pins.size(), 1u); } TEST_F(StaDesignTest, FindRegisterClkPins) { ClockSet *clks = nullptr; PinSet clk_pins = sta_->findRegisterClkPins(clks, RiseFallBoth::riseFall(), true, false, sta_->cmdMode()); EXPECT_GE(clk_pins.size(), 1u); } TEST_F(StaDesignTest, FindRegisterAsyncPins) { ASSERT_NO_THROW(( [&](){ ClockSet *clks = nullptr; sta_->findRegisterAsyncPins(clks, RiseFallBoth::riseFall(), true, false, sta_->cmdMode()); // May be empty if no async pins }() )); } TEST_F(StaDesignTest, FindRegisterOutputPins) { ClockSet *clks = nullptr; PinSet out_pins = sta_->findRegisterOutputPins(clks, RiseFallBoth::riseFall(), true, false, sta_->cmdMode()); EXPECT_GE(out_pins.size(), 1u); } TEST_F(StaDesignTest, FindRegisterInstancesWithClock) { Clock *clk = sta_->cmdSdc()->findClock("clk"); ASSERT_NE(clk, nullptr); ClockSet *clks = new ClockSet; clks->insert(clk); InstanceSet reg_insts = sta_->findRegisterInstances(clks, RiseFallBoth::riseFall(), true, false, sta_->cmdMode()); EXPECT_GE(reg_insts.size(), 1u); } TEST_F(StaDesignTest, FindRegisterDataPinsWithClock) { Clock *clk = sta_->cmdSdc()->findClock("clk"); ASSERT_NE(clk, nullptr); ClockSet *clks = new ClockSet; clks->insert(clk); PinSet data_pins = sta_->findRegisterDataPins(clks, RiseFallBoth::riseFall(), true, false, sta_->cmdMode()); EXPECT_GE(data_pins.size(), 1u); } TEST_F(StaDesignTest, FindRegisterClkPinsWithClock) { Clock *clk = sta_->cmdSdc()->findClock("clk"); ASSERT_NE(clk, nullptr); ClockSet *clks = new ClockSet; clks->insert(clk); PinSet clk_pins = sta_->findRegisterClkPins(clks, RiseFallBoth::riseFall(), true, false, sta_->cmdMode()); EXPECT_GE(clk_pins.size(), 1u); } TEST_F(StaDesignTest, FindRegisterOutputPinsWithClock) { Clock *clk = sta_->cmdSdc()->findClock("clk"); ASSERT_NE(clk, nullptr); ClockSet *clks = new ClockSet; clks->insert(clk); PinSet out_pins = sta_->findRegisterOutputPins(clks, RiseFallBoth::riseFall(), true, false, sta_->cmdMode()); EXPECT_GE(out_pins.size(), 1u); } TEST_F(StaDesignTest, FindRegisterRiseOnly) { ASSERT_NO_THROW(( [&](){ ClockSet *clks = nullptr; sta_->findRegisterClkPins(clks, RiseFallBoth::rise(), true, false, sta_->cmdMode()); }() )); } TEST_F(StaDesignTest, FindRegisterFallOnly) { ASSERT_NO_THROW(( [&](){ ClockSet *clks = nullptr; sta_->findRegisterClkPins(clks, RiseFallBoth::fall(), true, false, sta_->cmdMode()); }() )); } TEST_F(StaDesignTest, FindRegisterLatches) { ASSERT_NO_THROW(( [&](){ ClockSet *clks = nullptr; sta_->findRegisterInstances(clks, RiseFallBoth::riseFall(), false, true, sta_->cmdMode()); // No latches in this design }() )); } TEST_F(StaDesignTest, FindRegisterBothEdgeAndLatch) { ClockSet *clks = nullptr; InstanceSet insts = sta_->findRegisterInstances(clks, RiseFallBoth::riseFall(), true, true, sta_->cmdMode()); EXPECT_GE(insts.size(), 1u); } TEST_F(StaDesignTest, FindRegisterAsyncPinsWithClock) { Clock *clk = sta_->cmdSdc()->findClock("clk"); ASSERT_NE(clk, nullptr); ClockSet *clks = new ClockSet; clks->insert(clk); sta_->findRegisterAsyncPins(clks, RiseFallBoth::riseFall(), true, false, sta_->cmdMode()); } // --- PathEnd: detailed accessors --- TEST_F(StaDesignTest, PathEndType) { PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); for (const auto &end : ends) { end->type(); const char *name = end->typeName(); EXPECT_NE(name, nullptr); } } TEST_F(StaDesignTest, PathEndCheckRole) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); for (const auto &end : ends) { const TimingRole *role = end->checkRole(sta_); EXPECT_NE(role, nullptr); const TimingRole *generic_role = end->checkGenericRole(sta_); EXPECT_NE(generic_role, nullptr); } }() )); } TEST_F(StaDesignTest, PathEndVertex) { PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); for (const auto &end : ends) { Vertex *v = end->vertex(sta_); EXPECT_NE(v, nullptr); } } TEST_F(StaDesignTest, PathEndMinMax) { PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); for (const auto &end : ends) { const MinMax *mm = end->minMax(sta_); EXPECT_NE(mm, nullptr); const EarlyLate *el = end->pathEarlyLate(sta_); EXPECT_NE(el, nullptr); } } TEST_F(StaDesignTest, PathEndTransition) { PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); for (const auto &end : ends) { const RiseFall *rf = end->transition(sta_); EXPECT_NE(rf, nullptr); } } TEST_F(StaDesignTest, PathEndPathAnalysisPt) { PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); for (const auto &end : ends) { // pathAnalysisPt removed from PathEnd; use path->pathIndex instead size_t idx = end->path()->pathIndex(sta_); EXPECT_GE(idx, 0u); } } TEST_F(StaDesignTest, PathEndTargetClkAccessors) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); for (const auto &end : ends) { const Clock *tgt_clk = end->targetClk(sta_); EXPECT_NE(tgt_clk, nullptr); const ClockEdge *tgt_edge = end->targetClkEdge(sta_); EXPECT_NE(tgt_edge, nullptr); end->targetClkTime(sta_); end->targetClkOffset(sta_); end->targetClkArrival(sta_); end->targetClkDelay(sta_); end->targetClkInsertionDelay(sta_); } }() )); } TEST_F(StaDesignTest, PathEndTargetClkUncertainty) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); for (const auto &end : ends) { end->targetNonInterClkUncertainty(sta_); end->interClkUncertainty(sta_); end->targetClkUncertainty(sta_); end->targetClkMcpAdjustment(sta_); } }() )); } TEST_F(StaDesignTest, PathEndClkEarlyLate) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); for (const auto &end : ends) { const EarlyLate *el = end->clkEarlyLate(sta_); EXPECT_NE(el, nullptr); } }() )); } TEST_F(StaDesignTest, PathEndIsTypePredicates) { PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); for (const auto &end : ends) { bool is_check = end->isCheck(); bool is_uncon = end->isUnconstrained(); bool is_data = end->isDataCheck(); bool is_latch = end->isLatchCheck(); bool is_output = end->isOutputDelay(); bool is_gated = end->isGatedClock(); bool is_pd = end->isPathDelay(); // At least one should be true bool any = is_check || is_uncon || is_data || is_latch || is_output || is_gated || is_pd; EXPECT_TRUE(any); } } TEST_F(StaDesignTest, PathEndCrpr) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); for (const auto &end : ends) { end->crpr(sta_); end->checkCrpr(sta_); } }() )); } TEST_F(StaDesignTest, PathEndClkSkew) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); for (const auto &end : ends) { end->clkSkew(sta_); } }() )); } TEST_F(StaDesignTest, PathEndBorrow) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); for (const auto &end : ends) { end->borrow(sta_); } }() )); } TEST_F(StaDesignTest, PathEndSourceClkInsertionDelay) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); for (const auto &end : ends) { end->sourceClkInsertionDelay(sta_); } }() )); } TEST_F(StaDesignTest, PathEndTargetClkPath) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); for (const auto &end : ends) { Path *tgt_clk = end->targetClkPath(); EXPECT_NE(tgt_clk, nullptr); const Path *tgt_clk_const = const_cast(end)->targetClkPath(); EXPECT_NE(tgt_clk_const, nullptr); } }() )); } TEST_F(StaDesignTest, PathEndTargetClkEndTrans) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); for (const auto &end : ends) { const RiseFall *rf = end->targetClkEndTrans(sta_); EXPECT_NE(rf, nullptr); } }() )); } TEST_F(StaDesignTest, PathEndExceptPathCmp) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (ends.size() >= 2) { ends[0]->exceptPathCmp(ends[1], sta_); } }() )); } TEST_F(StaDesignTest, PathEndDataArrivalTimeOffset) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); for (const auto &end : ends) { end->dataArrivalTimeOffset(sta_); } }() )); } TEST_F(StaDesignTest, PathEndRequiredTimeOffset) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); for (const auto &end : ends) { end->requiredTimeOffset(sta_); } }() )); } TEST_F(StaDesignTest, PathEndMultiCyclePath) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); for (const auto &end : ends) { end->multiCyclePath(); end->pathDelay(); } }() )); } TEST_F(StaDesignTest, PathEndCmpNoCrpr) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (ends.size() >= 2) { PathEnd::cmpNoCrpr(ends[0], ends[1], sta_); } }() )); } TEST_F(StaDesignTest, PathEndLess2) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (ends.size() >= 2) { PathEnd::less(ends[0], ends[1], true, sta_); } }() )); } TEST_F(StaDesignTest, PathEndMacroClkTreeDelay) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); for (const auto &end : ends) { end->macroClkTreeDelay(sta_); } }() )); } // --- PathEnd: hold check --- TEST_F(StaDesignTest, FindPathEndsHold2) { ASSERT_NO_THROW(( [&](){ sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::min(), 10, 1, false, false, -INF, INF, false, group_names, false, true, false, false, false, false); }() )); } TEST_F(StaDesignTest, FindPathEndsHoldAccessors) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::min(), 10, 1, false, false, -INF, INF, false, group_names, false, true, false, false, false, false); for (const auto &end : ends) { end->slack(sta_); end->requiredTime(sta_); end->margin(sta_); } }() )); } // --- PathEnd: unconstrained --- TEST_F(StaDesignTest, FindPathEndsUnconstrained2) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, true, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); for (const auto &end : ends) { if (end->isUnconstrained()) { end->reportShort(sta_->reportPath()); end->requiredTime(sta_); } } }() )); } // --- ReportPath: various report functions --- TEST_F(StaDesignTest, ReportPathEndHeader) { ASSERT_NO_THROW(( [&](){ }() )); } TEST_F(StaDesignTest, ReportPathEndFooter) { ASSERT_NO_THROW(( [&](){ }() )); } TEST_F(StaDesignTest, ReportPathEnd2) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } TEST_F(StaDesignTest, ReportPathEnds2) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); sta_->reportPathEnds(&ends); }() )); } TEST_F(StaDesignTest, ReportPathEndFull) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::full); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } TEST_F(StaDesignTest, ReportPathEndFullClkPath) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::full_clock); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } TEST_F(StaDesignTest, ReportPathEndFullClkExpanded) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::full_clock_expanded); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } TEST_F(StaDesignTest, ReportPathEndShortFormat) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::shorter); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } TEST_F(StaDesignTest, ReportPathEndSummary) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::summary); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } TEST_F(StaDesignTest, ReportPathEndSlackOnly) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::slack_only); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } TEST_F(StaDesignTest, ReportPathEndJson) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::json); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } TEST_F(StaDesignTest, ReportPathFromVertex) { Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path && !path->isNull()) { sta_->reportPath(path); } } TEST_F(StaDesignTest, ReportPathFullWithPrevEnd) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (ends.size() >= 2) { sta_->setReportPathFormat(ReportPathFormat::full); sta_->reportPathEnd(ends[0]); sta_->reportPathEnd(ends[1]); } }() )); } TEST_F(StaDesignTest, ReportPathFieldOrder) { ASSERT_NO_THROW(( [&](){ StringSeq field_names; field_names.push_back("fanout"); field_names.push_back("capacitance"); field_names.push_back("slew"); sta_->setReportPathFieldOrder(field_names); }() )); } TEST_F(StaDesignTest, ReportPathFields) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFields(true, true, true, true, true, true, true, true); }() )); } TEST_F(StaDesignTest, ReportPathDigits) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathDigits(4); }() )); } TEST_F(StaDesignTest, ReportPathNoSplit) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathNoSplit(true); }() )); } // ReportPathSigmas removed — API no longer exists TEST_F(StaDesignTest, FindReportPathField2) { ReportField *field = sta_->findReportPathField("fanout"); EXPECT_NE(field, nullptr); field = sta_->findReportPathField("capacitance"); EXPECT_NE(field, nullptr); field = sta_->findReportPathField("slew"); EXPECT_NE(field, nullptr); } TEST_F(StaDesignTest, ReportPathFieldAccessors) { ReportPath *rpt = sta_->reportPath(); ReportField *slew = rpt->fieldSlew(); EXPECT_NE(slew, nullptr); ReportField *fanout = rpt->fieldFanout(); EXPECT_NE(fanout, nullptr); ReportField *cap = rpt->fieldCapacitance(); EXPECT_NE(cap, nullptr); } // --- ReportPath: MinPulseWidth check --- TEST_F(StaDesignTest, MinPulseWidthSlack2) { // minPulseWidthSlack removed; test reportMinPulseWidthChecks instead sta_->reportMinPulseWidthChecks(nullptr, 10, false, false, sta_->scenes()); } TEST_F(StaDesignTest, MinPulseWidthViolations2) { ASSERT_NO_THROW(( [&](){ sta_->reportMinPulseWidthChecks(nullptr, 10, true, false, sta_->scenes()); }() )); } TEST_F(StaDesignTest, MinPulseWidthChecksAll2) { // minPulseWidthChecks removed; test reportMinPulseWidthChecks sta_->reportMinPulseWidthChecks(nullptr, 10, false, false, sta_->scenes()); } TEST_F(StaDesignTest, MinPulseWidthCheckForPin) { ASSERT_NO_THROW(( [&](){ Pin *pin = findPin("r1/CK"); if (pin) { PinSeq pins; pins.push_back(pin); sta_->reportMinPulseWidthChecks(nullptr, 10, false, false, sta_->scenes()); } }() )); } // --- ReportPath: MinPeriod --- TEST_F(StaDesignTest, MinPeriodSlack2) { ASSERT_NO_THROW(( [&](){ sta_->reportMinPeriodChecks(nullptr, 10, false, false, sta_->scenes()); }() )); } TEST_F(StaDesignTest, MinPeriodViolations2) { ASSERT_NO_THROW(( [&](){ sta_->reportMinPeriodChecks(nullptr, 10, true, false, sta_->scenes()); }() )); } TEST_F(StaDesignTest, MinPeriodCheckVerbose) { ASSERT_NO_THROW(( [&](){ // minPeriodSlack removed // check variable removed // reportCheck removed // reportCheck removed }() )); } // --- ReportPath: MaxSkew --- TEST_F(StaDesignTest, MaxSkewSlack2) { ASSERT_NO_THROW(( [&](){ sta_->reportMaxSkewChecks(nullptr, 10, false, false, sta_->scenes()); }() )); } TEST_F(StaDesignTest, MaxSkewViolations2) { ASSERT_NO_THROW(( [&](){ sta_->reportMaxSkewChecks(nullptr, 10, true, false, sta_->scenes()); }() )); } TEST_F(StaDesignTest, MaxSkewCheckVerbose) { ASSERT_NO_THROW(( [&](){ // maxSkewSlack removed // check variable removed // reportCheck removed // reportCheck removed }() )); } TEST_F(StaDesignTest, ReportMaxSkewHeaderShort) { ASSERT_NO_THROW(( [&](){ ReportPath *rpt = sta_->reportPath(); rpt->reportMaxSkewHeaderShort(); }() )); } // --- ClkSkew / ClkLatency --- TEST_F(StaDesignTest, ReportClkSkewSetup) { Clock *clk = sta_->cmdSdc()->findClock("clk"); ASSERT_NE(clk, nullptr); ConstClockSeq clks; clks.push_back(clk); sta_->reportClkSkew(clks, sta_->scenes(), SetupHold::max(), false, 3); } TEST_F(StaDesignTest, ReportClkSkewHold) { Clock *clk = sta_->cmdSdc()->findClock("clk"); ASSERT_NE(clk, nullptr); ConstClockSeq clks; clks.push_back(clk); sta_->reportClkSkew(clks, sta_->scenes(), SetupHold::min(), false, 3); } TEST_F(StaDesignTest, ReportClkSkewWithInternalLatency) { Clock *clk = sta_->cmdSdc()->findClock("clk"); ASSERT_NE(clk, nullptr); ConstClockSeq clks; clks.push_back(clk); sta_->reportClkSkew(clks, sta_->scenes(), SetupHold::max(), true, 3); } TEST_F(StaDesignTest, FindWorstClkSkew2) { ASSERT_NO_THROW(( [&](){ sta_->findWorstClkSkew(SetupHold::max(), false); }() )); } TEST_F(StaDesignTest, ReportClkLatency2) { Clock *clk = sta_->cmdSdc()->findClock("clk"); ASSERT_NE(clk, nullptr); ConstClockSeq clks; clks.push_back(clk); sta_->reportClkLatency(clks, sta_->scenes(), false, 3); } TEST_F(StaDesignTest, ReportClkLatencyWithInternal) { Clock *clk = sta_->cmdSdc()->findClock("clk"); ASSERT_NE(clk, nullptr); ConstClockSeq clks; clks.push_back(clk); sta_->reportClkLatency(clks, sta_->scenes(), true, 3); } TEST_F(StaDesignTest, FindClkDelays2) { Clock *clk = sta_->cmdSdc()->findClock("clk"); ASSERT_NE(clk, nullptr); sta_->findClkDelays(clk, sta_->cmdScene(), false); } TEST_F(StaDesignTest, FindClkMinPeriod2) { Clock *clk = sta_->cmdSdc()->findClock("clk"); ASSERT_NE(clk, nullptr); sta_->findClkMinPeriod(clk, false); } TEST_F(StaDesignTest, FindClkMinPeriodWithPorts) { Clock *clk = sta_->cmdSdc()->findClock("clk"); ASSERT_NE(clk, nullptr); sta_->findClkMinPeriod(clk, true); } // --- Property tests --- TEST_F(StaDesignTest, PropertyGetLibrary) { Network *network = sta_->cmdNetwork(); LibraryIterator *lib_iter = network->libraryIterator(); if (lib_iter->hasNext()) { Library *lib = lib_iter->next(); Properties &props = sta_->properties(); PropertyValue pv = props.getProperty(lib, "name"); EXPECT_EQ(pv.type(), PropertyValue::Type::string); } delete lib_iter; } TEST_F(StaDesignTest, PropertyGetCell) { Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Cell *cell = network->cell(top); if (cell) { Properties &props = sta_->properties(); PropertyValue pv = props.getProperty(cell, "name"); EXPECT_EQ(pv.type(), PropertyValue::Type::string); } } TEST_F(StaDesignTest, PropertyGetLibertyLibrary) { Properties &props = sta_->properties(); PropertyValue pv = props.getProperty(lib_, "name"); EXPECT_EQ(pv.type(), PropertyValue::Type::string); } TEST_F(StaDesignTest, PropertyGetLibertyCell) { LibertyCell *cell = lib_->findLibertyCell("DFF_X1"); ASSERT_NE(cell, nullptr); Properties &props = sta_->properties(); PropertyValue pv = props.getProperty(cell, "name"); EXPECT_EQ(pv.type(), PropertyValue::Type::string); } TEST_F(StaDesignTest, PropertyGetLibertyPort2) { LibertyCell *cell = lib_->findLibertyCell("DFF_X1"); ASSERT_NE(cell, nullptr); LibertyPort *port = cell->findLibertyPort("D"); ASSERT_NE(port, nullptr); Properties &props = sta_->properties(); PropertyValue pv = props.getProperty(port, "name"); EXPECT_EQ(pv.type(), PropertyValue::Type::string); } TEST_F(StaDesignTest, PropertyGetInstance) { Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); InstanceChildIterator *child_iter = network->childIterator(top); if (child_iter->hasNext()) { Instance *inst = child_iter->next(); Properties &props = sta_->properties(); PropertyValue pv = props.getProperty(inst, "name"); EXPECT_EQ(pv.type(), PropertyValue::Type::string); } delete child_iter; } TEST_F(StaDesignTest, PropertyGetPin) { Pin *pin = findPin("r1/Q"); ASSERT_NE(pin, nullptr); Properties &props = sta_->properties(); PropertyValue pv = props.getProperty(pin, "name"); EXPECT_EQ(pv.type(), PropertyValue::Type::string); } TEST_F(StaDesignTest, PropertyGetPinDirection) { Pin *pin = findPin("r1/Q"); ASSERT_NE(pin, nullptr); Properties &props = sta_->properties(); PropertyValue pv = props.getProperty(pin, "direction"); EXPECT_EQ(pv.type(), PropertyValue::Type::string); } TEST_F(StaDesignTest, PropertyGetNet) { Network *network = sta_->cmdNetwork(); Pin *pin = findPin("r1/Q"); ASSERT_NE(pin, nullptr); Net *net = network->net(pin); if (net) { Properties &props = sta_->properties(); PropertyValue pv = props.getProperty(net, "name"); EXPECT_EQ(pv.type(), PropertyValue::Type::string); } } TEST_F(StaDesignTest, PropertyGetClock2) { Clock *clk = sta_->cmdSdc()->findClock("clk"); ASSERT_NE(clk, nullptr); Properties &props = sta_->properties(); PropertyValue pv = props.getProperty(clk, "name"); EXPECT_EQ(pv.type(), PropertyValue::Type::string); } TEST_F(StaDesignTest, PropertyGetClockPeriod) { Clock *clk = sta_->cmdSdc()->findClock("clk"); ASSERT_NE(clk, nullptr); Properties &props = sta_->properties(); PropertyValue pv = props.getProperty(clk, "period"); EXPECT_EQ(pv.type(), PropertyValue::Type::float_); } TEST_F(StaDesignTest, PropertyGetPort2) { Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Cell *cell = network->cell(top); CellPortIterator *port_iter = network->portIterator(cell); if (port_iter->hasNext()) { Port *port = port_iter->next(); Properties &props = sta_->properties(); PropertyValue pv = props.getProperty(port, "name"); EXPECT_EQ(pv.type(), PropertyValue::Type::string); } delete port_iter; } TEST_F(StaDesignTest, PropertyGetEdge2) { Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); VertexInEdgeIterator edge_iter(v, sta_->graph()); if (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); Properties &props = sta_->properties(); props.getProperty(edge, "from_pin"); } } TEST_F(StaDesignTest, PropertyGetPathEndSlack) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (!ends.empty()) { Properties &props = sta_->properties(); props.getProperty(ends[0], "startpoint"); props.getProperty(ends[0], "endpoint"); } }() )); } TEST_F(StaDesignTest, PropertyGetPathEndMore) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (!ends.empty()) { Properties &props = sta_->properties(); props.getProperty(ends[0], "startpoint_clock"); props.getProperty(ends[0], "endpoint_clock"); props.getProperty(ends[0], "points"); } }() )); } // --- Property: pin arrival/slack --- TEST_F(StaDesignTest, PinArrival2) { Pin *pin = findPin("r1/Q"); ASSERT_NE(pin, nullptr); sta_->arrival(pin, RiseFallBoth::rise(), MinMax::max()); } TEST_F(StaDesignTest, PinSlack) { Pin *pin = findPin("r3/D"); ASSERT_NE(pin, nullptr); sta_->slack(pin, RiseFallBoth::riseFall(), sta_->scenes(), MinMax::max()); sta_->slack(pin, RiseFallBoth::rise(), sta_->scenes(), MinMax::max()); } TEST_F(StaDesignTest, NetSlack2) { Network *network = sta_->cmdNetwork(); Pin *pin = findPin("r3/D"); ASSERT_NE(pin, nullptr); Net *net = network->net(pin); if (net) { sta_->slack(net, MinMax::max()); } } // --- Search: various methods --- TEST_F(StaDesignTest, SearchIsClock) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); Vertex *v = findVertex("r1/CK"); if (v) { (void)(search->clocks(v, sta_->cmdMode()).size() > 0); } }() )); } TEST_F(StaDesignTest, SearchIsGenClkSrc2) { Search *search = sta_->search(); (void)search; Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); (void)true /* Search::isGenClkSrc removed */; } TEST_F(StaDesignTest, SearchClocks) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); Vertex *v = findVertex("r1/CK"); if (v) { search->clocks(v, sta_->cmdMode()); } }() )); } TEST_F(StaDesignTest, SearchClockDomains) { Search *search = sta_->search(); Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); search->clockDomains(v, sta_->cmdMode()); } TEST_F(StaDesignTest, SearchClockDomainsPin) { Search *search = sta_->search(); Pin *pin = findPin("r1/Q"); ASSERT_NE(pin, nullptr); search->clockDomains(pin, sta_->cmdMode()); } TEST_F(StaDesignTest, SearchClocksPin) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); Pin *pin = findPin("r1/CK"); if (pin) { search->clocks(pin, sta_->cmdMode()); } }() )); } TEST_F(StaDesignTest, SearchIsEndpoint2) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); Vertex *v_data = findVertex("r3/D"); if (v_data) { EXPECT_TRUE(search->isEndpoint(v_data)); } Vertex *v_out = findVertex("r1/Q"); if (v_out) { EXPECT_FALSE(search->isEndpoint(v_out)); } }() )); } TEST_F(StaDesignTest, SearchHavePathGroups) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); (void)search; (void)true /* Search::havePathGroups removed */; }() )); } TEST_F(StaDesignTest, SearchFindPathGroup) { Search *search = sta_->search(); (void)search; Clock *clk = sta_->cmdSdc()->findClock("clk"); ASSERT_NE(clk, nullptr); // Search::findPathGroup removed } TEST_F(StaDesignTest, SearchClkInfoCount) { Search *search = sta_->search(); int count = search->clkInfoCount(); EXPECT_GE(count, 0); } TEST_F(StaDesignTest, SearchTagGroupCount) { Search *search = sta_->search(); TagGroupIndex count = search->tagGroupCount(); EXPECT_GE(count, 0u); } TEST_F(StaDesignTest, SearchTagGroupByIndex) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); TagGroupIndex count = search->tagGroupCount(); if (count > 0) { TagGroup *tg = search->tagGroup(0); EXPECT_NE(tg, nullptr); } }() )); } TEST_F(StaDesignTest, SearchReportTagGroups2) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); search->reportTagGroups(); }() )); } TEST_F(StaDesignTest, SearchReportArrivals2) { Search *search = sta_->search(); Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); search->reportArrivals(v, false); search->reportArrivals(v, true); } TEST_F(StaDesignTest, SearchSeedArrival) { // seedArrival(Vertex*) removed; seedArrivals() is now protected. // Exercise search through Sta::arrival instead. Vertex *v = findVertex("in1"); if (v) { sta_->arrival(v, RiseFallBoth::rise(), sta_->scenes(), MinMax::max()); } } TEST_F(StaDesignTest, SearchPathClkPathArrival2) { Search *search = sta_->search(); Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path && !path->isNull()) { search->pathClkPathArrival(path); } } TEST_F(StaDesignTest, SearchFindClkArrivals) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); search->findClkArrivals(); }() )); } } // namespace sta