Global Metrics

path: .metrics.nom.total
old: 51.0
new: 12.0

path: .metrics.nom.functions
old: 51.0
new: 12.0

path: .metrics.mi.mi_sei
old: -145.02940731207346
new: -6.920660213702103

path: .metrics.mi.mi_original
old: -89.05065460865201
new: 32.606329431818594

path: .metrics.mi.mi_visual_studio
old: 0.0
new: 19.068028907496252

path: .metrics.halstead.bugs
old: 10.720722893634816
new: 1.3441805972774128

path: .metrics.halstead.N2
old: 2841.0
new: 311.0

path: .metrics.halstead.vocabulary
old: 718.0
new: 136.0

path: .metrics.halstead.estimated_program_length
old: 6593.665498457801
new: 858.575864976936

path: .metrics.halstead.effort
old: 5767903.529528152
new: 256075.6686748247

path: .metrics.halstead.length
old: 7451.0
new: 787.0

path: .metrics.halstead.N1
old: 4610.0
new: 476.0

path: .metrics.halstead.difficulty
old: 81.58983799705449
new: 45.90952380952381

path: .metrics.halstead.time
old: 320439.08497378626
new: 14226.42603749026

path: .metrics.halstead.level
old: 0.012256428307114686
new: 0.02178197282439581

path: .metrics.halstead.purity_ratio
old: 0.8849369881167362
new: 1.090947731863959

path: .metrics.halstead.volume
old: 70693.89609201555
new: 5577.8332560640165

path: .metrics.halstead.n1
old: 39.0
new: 31.0

path: .metrics.halstead.n2
old: 679.0
new: 105.0

path: .metrics.nargs.sum
old: 59.0
new: 5.0

path: .metrics.nargs.average
old: 1.156862745098039
new: 0.4166666666666667

path: .metrics.loc.blank
old: 196.0
new: 19.0

path: .metrics.loc.lloc
old: 723.0
new: 66.0

path: .metrics.loc.cloc
old: 172.0
new: 11.0

path: .metrics.loc.ploc
old: 1388.0
new: 163.0

path: .metrics.loc.sloc
old: 1756.0
new: 193.0

path: .metrics.nexits.sum
old: 194.0
new: 5.0

path: .metrics.nexits.average
old: 3.803921568627451
new: 0.4166666666666667

path: .metrics.cognitive.sum
old: 154.0
new: 26.0

path: .metrics.cognitive.average
old: 3.019607843137255
new: 2.1666666666666665

path: .metrics.cyclomatic.sum
old: 352.0
new: 36.0

path: .metrics.cyclomatic.average
old: 6.285714285714286
new: 2.1176470588235294

Spaces Data

Minimal test - lines (24, 36)

path: .spaces[0].spaces[0].metrics.halstead.N2
old: 456.0
new: 18.0

path: .spaces[0].spaces[0].metrics.halstead.N1
old: 551.0
new: 25.0

path: .spaces[0].spaces[0].metrics.halstead.estimated_program_length
old: 815.4423126656951
new: 61.74860596185444

path: .spaces[0].spaces[0].metrics.halstead.vocabulary
old: 122.0
new: 19.0

path: .spaces[0].spaces[0].metrics.halstead.purity_ratio
old: 0.8097738953979098
new: 1.4360140921361495

path: .spaces[0].spaces[0].metrics.halstead.level
old: 0.10263157894736843
new: 0.1234567901234568

path: .spaces[0].spaces[0].metrics.halstead.effort
old: 68002.97306645678
new: 1479.5531529324007

path: .spaces[0].spaces[0].metrics.halstead.n2
old: 117.0
new: 10.0

path: .spaces[0].spaces[0].metrics.halstead.volume
old: 6979.252498925827
new: 182.66088307807416

path: .spaces[0].spaces[0].metrics.halstead.time
old: 3777.942948136488
new: 82.19739738513337

path: .spaces[0].spaces[0].metrics.halstead.difficulty
old: 9.743589743589745
new: 8.1

path: .spaces[0].spaces[0].metrics.halstead.bugs
old: 0.5553464655217764
new: 0.04328118336830632

path: .spaces[0].spaces[0].metrics.halstead.length
old: 1007.0
new: 43.0

path: .spaces[0].spaces[0].metrics.halstead.n1
old: 5.0
new: 9.0

path: .spaces[0].spaces[0].metrics.nexits.average
old: null
new: 0.3333333333333333

path: .spaces[0].spaces[0].metrics.nexits.sum
old: 0.0
new: 1.0

path: .spaces[0].spaces[0].metrics.loc.sloc
old: 173.0
new: 13.0

path: .spaces[0].spaces[0].metrics.loc.ploc
old: 171.0
new: 11.0

path: .spaces[0].spaces[0].metrics.loc.lloc
old: 0.0
new: 4.0

path: .spaces[0].spaces[0].metrics.mi.mi_visual_studio
old: 24.130439332522997
new: 59.32639617717958

path: .spaces[0].spaces[0].metrics.mi.mi_original
old: 41.263051258614325
new: 101.44813746297709

path: .spaces[0].spaces[0].metrics.mi.mi_sei
old: -16.069032709858277
new: 71.06515227086403

path: .spaces[0].spaces[0].metrics.cognitive.average
old: null
new: 0.0

path: .spaces[0].spaces[0].metrics.nom.functions
old: 0.0
new: 3.0

path: .spaces[0].spaces[0].metrics.nom.total
old: 0.0
new: 3.0

path: .spaces[0].spaces[0].metrics.cyclomatic.sum
old: 1.0
new: 4.0

path: .spaces[0].spaces[0].metrics.nargs.average
old: null
new: 0.0

Code

struct Object {
  Object() : mExpired(false) { Touch(); }
  void Touch() {
    mLastUsed = PR_IntervalNow();
    mExpired = false;
  }

  nsExpirationState mExpiration;
  nsExpirationState* GetExpirationState() { return &mExpiration; }

  PRIntervalTime mLastUsed;
  bool mExpired;
};

Minimal test - lines (22, 193)

path: .spaces[0].metrics.nargs.average
old: null
new: 0.4166666666666667

path: .spaces[0].metrics.nargs.sum
old: 0.0
new: 5.0

path: .spaces[0].metrics.cyclomatic.sum
old: 2.0
new: 35.0

path: .spaces[0].metrics.cyclomatic.average
old: 1.0
new: 2.1875

path: .spaces[0].metrics.loc.blank
old: 1.0
new: 18.0

path: .spaces[0].metrics.loc.cloc
old: 1.0
new: 5.0

path: .spaces[0].metrics.loc.sloc
old: 175.0
new: 172.0

path: .spaces[0].metrics.loc.ploc
old: 173.0
new: 149.0

path: .spaces[0].metrics.loc.lloc
old: 0.0
new: 66.0

path: .spaces[0].metrics.nom.functions
old: 0.0
new: 12.0

path: .spaces[0].metrics.nom.total
old: 0.0
new: 12.0

path: .spaces[0].metrics.halstead.estimated_program_length
old: 823.7615202991341
new: 769.711437679691

path: .spaces[0].metrics.halstead.N2
old: 457.0
new: 300.0

path: .spaces[0].metrics.halstead.n1
old: 5.0
new: 31.0

path: .spaces[0].metrics.halstead.effort
old: 67823.80701484095
new: 267397.1916252625

path: .spaces[0].metrics.halstead.time
old: 3767.989278602274
new: 14855.399534736804

path: .spaces[0].metrics.halstead.vocabulary
old: 123.0
new: 125.0

path: .spaces[0].metrics.halstead.n2
old: 118.0
new: 94.0

path: .spaces[0].metrics.halstead.purity_ratio
old: 0.8164137961339287
new: 0.9918961825769214

path: .spaces[0].metrics.halstead.N1
old: 552.0
new: 476.0

path: .spaces[0].metrics.halstead.difficulty
old: 9.682203389830509
new: 49.46808510638298

path: .spaces[0].metrics.halstead.length
old: 1009.0
new: 776.0

path: .spaces[0].metrics.halstead.level
old: 0.10328227571115974
new: 0.02021505376344086

path: .spaces[0].metrics.halstead.volume
old: 7004.997135887293
new: 5405.44860489778

path: .spaces[0].metrics.halstead.bugs
old: 0.554370596657102
new: 1.3835131979417077

path: .spaces[0].metrics.cognitive.sum
old: 0.0
new: 26.0

path: .spaces[0].metrics.cognitive.average
old: null
new: 2.1666666666666665

path: .spaces[0].metrics.nexits.average
old: null
new: 0.4166666666666667

path: .spaces[0].metrics.nexits.sum
old: 0.0
new: 5.0

path: .spaces[0].metrics.mi.mi_original
old: 40.82769616293768
new: 34.86574330686953

path: .spaces[0].metrics.mi.mi_sei
old: -10.753271648302269
new: -8.782790560890827

path: .spaces[0].metrics.mi.mi_visual_studio
old: 23.87584570932028
new: 20.389323571268733

Code

namespace TestExpirationTracker {

struct Object {
  Object() : mExpired(false) { Touch(); }
  void Touch() {
    mLastUsed = PR_IntervalNow();
    mExpired = false;
  }

  nsExpirationState mExpiration;
  nsExpirationState* GetExpirationState() { return &mExpiration; }

  PRIntervalTime mLastUsed;
  bool mExpired;
};

static bool error;
static uint32_t periodMS = 100;
static uint32_t ops = 1000;
static uint32_t iterations = 2;
static bool logging = 0;
static uint32_t sleepPeriodMS = 50;
static uint32_t upperBoundSlackMS = 1200;  // allow this much error
static uint32_t lowerBoundSlackMS = 60;

template 
class Tracker : public nsExpirationTracker {
 public:
  Tracker() : nsExpirationTracker(periodMS, "Tracker") {
    Object* obj = new Object();
    mUniverse.AppendElement(obj);
    LogAction(obj, "Created");
  }

  nsTArray> mUniverse;

  void LogAction(Object* aObj, const char* aAction) {
    if (logging) {
      printf("%d %p(%d): %s\n", PR_IntervalNow(), static_cast(aObj),
             aObj->mLastUsed, aAction);
    }
  }

  void DoRandomOperation() {
    using mozilla::UniquePtr;

    Object* obj;
    switch (rand() & 0x7) {
      case 0: {
        if (mUniverse.Length() < 50) {
          obj = new Object();
          mUniverse.AppendElement(obj);
          nsExpirationTracker::AddObject(obj);
          LogAction(obj, "Created and added");
        }
        break;
      }
      case 4: {
        if (mUniverse.Length() < 50) {
          obj = new Object();
          mUniverse.AppendElement(obj);
          LogAction(obj, "Created");
        }
        break;
      }
      case 1: {
        UniquePtr& objref =
            mUniverse[uint32_t(rand()) % mUniverse.Length()];
        if (objref->mExpiration.IsTracked()) {
          nsExpirationTracker::RemoveObject(objref.get());
          LogAction(objref.get(), "Removed");
        }
        break;
      }
      case 2: {
        UniquePtr& objref =
            mUniverse[uint32_t(rand()) % mUniverse.Length()];
        if (!objref->mExpiration.IsTracked()) {
          objref->Touch();
          nsExpirationTracker::AddObject(objref.get());
          LogAction(objref.get(), "Added");
        }
        break;
      }
      case 3: {
        UniquePtr& objref =
            mUniverse[uint32_t(rand()) % mUniverse.Length()];
        if (objref->mExpiration.IsTracked()) {
          objref->Touch();
          nsExpirationTracker::MarkUsed(objref.get());
          LogAction(objref.get(), "Marked used");
        }
        break;
      }
    }
  }

 protected:
  void NotifyExpired(Object* aObj) override {
    LogAction(aObj, "Expired");
    PRIntervalTime now = PR_IntervalNow();
    uint32_t timeDiffMS = (now - aObj->mLastUsed) * 1000 / PR_TicksPerSecond();
    // See the comment for NotifyExpired in nsExpirationTracker.h for these
    // bounds
    uint32_t lowerBoundMS = (K - 1) * periodMS - lowerBoundSlackMS;
    uint32_t upperBoundMS = K * (periodMS + sleepPeriodMS) + upperBoundSlackMS;
    if (logging) {
      printf("Checking: %d-%d = %d [%d,%d]\n", now, aObj->mLastUsed, timeDiffMS,
             lowerBoundMS, upperBoundMS);
    }
    if (timeDiffMS < lowerBoundMS || timeDiffMS > upperBoundMS) {
      EXPECT_LT(timeDiffMS, periodMS);
      EXPECT_TRUE(aObj->mExpired);
    }
    aObj->Touch();
    aObj->mExpired = true;
    DoRandomOperation();
    DoRandomOperation();
    DoRandomOperation();
  }
};

template 
static bool test_random() {
  srand(K);
  error = false;

  for (uint32_t j = 0; j < iterations; ++j) {
    Tracker tracker;

    uint32_t i = 0;
    for (i = 0; i < ops; ++i) {
      if ((rand() & 0xF) == 0) {
        // Simulate work that takes time
        if (logging) {
          printf("SLEEPING for %dms (%d)\n", sleepPeriodMS, PR_IntervalNow());
        }
        PR_Sleep(PR_MillisecondsToInterval(sleepPeriodMS));
        // Process pending timer events
        NS_ProcessPendingEvents(nullptr);
      }
      tracker.DoRandomOperation();
    }
  }

  return !error;
}

static bool test_random3() { return test_random<3>(); }
static bool test_random4() { return test_random<4>(); }
static bool test_random8() { return test_random<8>(); }

typedef bool (*TestFunc)();
#define DECL_TEST(name) \
  { #name, name }

static const struct Test {
  const char* name;
  TestFunc func;
} tests[] = {DECL_TEST(test_random3),
             DECL_TEST(test_random4),
             DECL_TEST(test_random8),
             {nullptr, nullptr}};

TEST(ExpirationTracker, main)
{
  for (const TestExpirationTracker::Test* t = tests; t->name != nullptr; ++t) {
    EXPECT_TRUE(t->func());
  }
}

}  // namespace TestExpirationTracker