]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#3285] Removed GENERATE code and tests
authorFrancis Dupont <fdupont@isc.org>
Mon, 11 Mar 2024 16:22:35 +0000 (17:22 +0100)
committerFrancis Dupont <fdupont@isc.org>
Mon, 11 Mar 2024 16:22:35 +0000 (17:22 +0100)
src/lib/dns/master_loader.cc
src/lib/dns/tests/master_loader_unittest.cc

index 0f42977e7d6b2eb4e62b4a9e460f936ba7607159..e771bd3e62ebe16988b039337fa9080cf8db3191 100644 (file)
@@ -222,20 +222,6 @@ private:
     /// handled in \c loadIncremental().
     MasterToken handleInitialToken();
 
-    /// \brief Helper method for \c doGenerate().
-    ///
-    /// This is a helper method for \c doGenerate() that processes the
-    /// LHS or RHS for a single iteration in the range that is requested
-    /// by the $GENERATE directive and returns a generated string (that
-    /// is used to build a name (LHS) or RDATA (RHS) for an RR). See the
-    /// commented implementation for details.
-    std::string generateForIter(const std::string& str, const int it);
-
-    /// \brief Process the $GENERATE directive.
-    ///
-    /// See the commented implementation for details.
-    void doGenerate();
-
     /// \brief Process the $ORIGIN directive.
     void doOrigin(bool is_optional) {
         // Parse and create the new origin. It is relative to the previous
@@ -458,9 +444,6 @@ private:
         } else if (iequals(directive, "ORIGIN")) {
             doOrigin(false);
             eatUntilEOL(true);
-        } else if (iequals(directive, "GENERATE")) {
-            doGenerate();
-            eatUntilEOL(true);
         } else if (iequals(directive, "TTL")) {
             setDefaultTTL(RRTTL(getString()), false);
             eatUntilEOL(true);
@@ -551,318 +534,6 @@ public:
     size_t rr_count_;    // number of RRs successfully loaded
 };
 
-namespace { // begin unnamed namespace
-
-/// \brief Generate a dotted nibble sequence.
-///
-/// This method generates a dotted nibble sequence and returns it as a
-/// string. The nibbles are appended from the least significant digit
-/// (in hex representation of \c num) to the most significant digit with
-/// dots ('.') to separate the digits. If \c width is non-zero and the
-/// dotted nibble sequence has not filled the requested width, the rest
-/// of the width is filled with a dotted nibble sequence of 0 nibbles.
-///
-/// Some sample representations:
-///
-/// num = 0x1234, width = 0
-/// "4.3.2.1"
-///
-/// num = 0x1234, width = 1
-/// "4.3.2.1"
-///
-/// num = 0x1234, width = 8
-/// "4.3.2.1"
-///
-/// num = 0x1234, width = 9
-/// "4.3.2.1."
-///
-/// num = 0x1234, width = 10
-/// "4.3.2.1.0"
-///
-/// num = 0x1234, width = 11
-/// "4.3.2.1.0."
-///
-/// num = 0xabcd, width = 0, uppercase = true
-/// "D.C.B.A"
-///
-/// num = 0, width = 0
-/// "0"
-///
-/// num = 0, width = 1
-/// "0"
-///
-/// num = 0, width = 2
-/// "0."
-///
-/// num = 0, width = 3
-/// "0.0"
-///
-/// \param num The number for which the dotted nibble sequence should be
-/// generated.
-/// \param width The width of the generated string. This is only
-/// meaningful when it is larger than the dotted nibble sequence
-/// representation of \c num.
-/// \param uppercase Whether to use uppercase characters in nibble
-/// sequence.
-/// \return A string containing the dotted nibble sequence.
-std::string
-genNibbles(int num, unsigned int width, bool uppercase) {
-    static const char *hex = "0123456789abcdef0123456789ABCDEF";
-    std::string rstr;
-
-    do {
-        char ch = hex[(num & 0x0f) + (uppercase ? 16 : 0)];
-        num >>= 4;
-        rstr.push_back(ch);
-
-        if (width > 0) {
-            --width;
-        }
-
-        // If width is non zero then we need to add a label separator.
-        // If value is non zero then we need to add another label and
-        // that requires a label separator.
-        if (width > 0 || num != 0) {
-            rstr.push_back('.');
-
-            if (width > 0) {
-                --width;
-            }
-        }
-    } while ((num != 0) || (width > 0));
-
-    return (rstr);
-}
-
-} // end unnamed namespace
-
-std::string
-MasterLoader::MasterLoaderImpl::generateForIter(const std::string& str,
-                                                const int num) {
-  std::string rstr;
-
-  for (auto it = str.begin(); it != str.end();) {
-      switch (*it) {
-      case '$':
-          // This is the case when the '$' character is encountered in
-          // the LHS or RHS. A computed value is added in its place in
-          // the generated string.
-          ++it;
-          if ((it != str.end()) && (*it == '$')) {
-              rstr.push_back('$');
-              ++it;
-              continue;
-          }
-
-          // The str.end() check is required.
-          if ((it == str.end()) || (*it != '{')) {
-              // There is no modifier (between {}), so just copy the
-              // passed number into the generated string.
-              rstr += boost::str(boost::format("%d") % num);
-          } else {
-              // There is a modifier (between {}). Parse it and handle
-              // the various cases below.
-              const char* scan_str =
-                  str.c_str() + std::distance(str.begin(), it);
-              int offset = 0;
-              unsigned int width;
-              char base[2] = {'d', 0}; // char plus null byte
-              // cppcheck-suppress invalidscanf_libc
-              const int n = sscanf(scan_str, "{%d,%u,%1[doxXnN]}",
-                                   &offset, &width, base);
-              switch (n) {
-              case 1:
-                  // Only 1 item was matched (the offset). Copy (num +
-                  // offset) into the generated string.
-                  rstr += boost::str(boost::format("%d") % (num + offset));
-                  break;
-
-              case 2: {
-                  // 2 items were matched (the offset and width). Copy
-                  // (num + offset) and format it according to the width
-                  // into the generated string.
-                  const std::string fmt =
-                      boost::str(boost::format("%%0%ud") % width);
-                  rstr += boost::str(boost::format(fmt) % (num + offset));
-                  break;
-              }
-
-              case 3:
-                  // 3 items were matched (offset, width and base).
-                  if ((base[0] == 'n') || (base[0] == 'N')) {
-                      // The base is requesting nibbles. Format it
-                      // specially (see genNibbles() documentation).
-                      rstr += genNibbles(num + offset, width, (base[0] == 'N'));
-                  } else {
-                      // The base is not requesting nibbles. Copy (num +
-                      // offset) and format it according to the width
-                      // and base into the generated string.
-                      const std::string fmt =
-                          boost::str(boost::format("%%0%u%c") % width % base[0]);
-                      rstr += boost::str(boost::format(fmt) % (num + offset));
-                  }
-                  break;
-
-              default:
-                  // Any other case in the modifiers is an error.
-                  reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
-                              "Invalid $GENERATE format modifiers");
-                  return ("");
-              }
-
-              // Find the closing brace. Careful that 'it' can be equal
-              // to str.end() here.
-              while ((it != str.end()) && (*it != '}')) {
-                  ++it;
-              }
-              // Skip past the closing brace (if there is one).
-              if (it != str.end()) {
-                  ++it;
-              }
-          }
-          break;
-
-      case '\\':
-          // This is the case when the '\' character is encountered in
-          // the LHS or RHS. The '\' and the following character are
-          // copied as-is into the generated string. This is usually
-          // used for escaping the $ character.
-          rstr.push_back(*it);
-          ++it;
-          if (it == str.end()) {
-              continue;
-          }
-          rstr.push_back(*it);
-          ++it;
-          break;
-
-      default:
-          // This is the default case that handles all other
-          // characters. They are copied as-is into the generated
-          // string.
-          rstr.push_back(*it);
-          ++it;
-          break;
-      }
-  }
-
-  return (rstr);
-}
-
-void
-MasterLoader::MasterLoaderImpl::doGenerate() {
-    // Parse the range token
-    const MasterToken& range_token = lexer_.getNextToken(MasterToken::STRING);
-    if (range_token.getType() != MasterToken::STRING) {
-        reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
-                    "Invalid $GENERATE syntax");
-        return;
-    }
-    const std::string range = range_token.getString();
-
-    // Parse the LHS token
-    const MasterToken& lhs_token = lexer_.getNextToken(MasterToken::STRING);
-    if (lhs_token.getType() != MasterToken::STRING) {
-        reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
-                    "Invalid $GENERATE syntax");
-        return;
-    }
-    const std::string lhs = lhs_token.getString();
-
-    // Parse the TTL, RR class and RR type tokens. Note that TTL and RR
-    // class may come in any order, or may be missing (either or
-    // both). If TTL is missing, we expect that it was either specified
-    // explicitly using $TTL, or is implicitly known from a previous RR,
-    // or that this is the SOA RR from which the MINIMUM field is
-    // used. It's unlikely that $GENERATE will be used with an SOA RR,
-    // but it's possible. The parsing happens within the parseRRParams()
-    // helper method which is called below.
-    const MasterToken& param_token = lexer_.getNextToken(MasterToken::STRING);
-    if (param_token.getType() != MasterToken::STRING) {
-        reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
-                    "Invalid $GENERATE syntax");
-        return;
-    }
-
-    bool explicit_ttl = false;
-    const RRType rrtype = parseRRParams(explicit_ttl, param_token);
-
-    // Parse the RHS token. It can be a quoted string.
-    const MasterToken& rhs_token = lexer_.getNextToken(MasterToken::QSTRING);
-    if ((rhs_token.getType() != MasterToken::QSTRING) &&
-        (rhs_token.getType() != MasterToken::STRING))
-    {
-        reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
-                    "Invalid $GENERATE syntax");
-        return;
-    }
-    const std::string rhs = rhs_token.getString();
-
-    // Range can be one of two forms: start-stop or start-stop/step. If
-    // the first form is used, then step is set to 1. All of start, stop
-    // and step must be positive.
-    unsigned int start;
-    unsigned int stop;
-    unsigned int step;
-    // cppcheck-suppress invalidscanf_libc
-    const int n = sscanf(range.c_str(), "%u-%u/%u", &start, &stop, &step);
-    if ((n < 2) || (stop < start)) {
-        reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
-                    "$GENERATE: invalid range: " + range);
-        return;
-    }
-
-    if (n == 2) {
-        step = 1;
-    }
-
-    // Generate and add the records.
-    for (unsigned int i = start; i <= stop; i += step) {
-        // Get generated strings for LHS and RHS. LHS goes to form the
-        // name, RHS goes to form the RDATA of the RR.
-        const std::string generated_name = generateForIter(lhs, i);
-        const std::string generated_rdata = generateForIter(rhs, i);
-        if (generated_name.empty() || generated_rdata.empty()) {
-            // The error should have been sent to the callbacks already
-            // by generateForIter().
-            reportError(lexer_.getSourceName(), lexer_.getSourceLine(),
-                        "$GENERATE error");
-            return;
-        }
-
-        // generateForIter() can return a string with a trailing '.' in
-        // case of a nibble representation. So we cannot use the
-        // relative Name constructor. We use concatenate() which is
-        // expensive, but keeps the generated LHS-based Name within the
-        // active origin.
-        last_name_.reset
-            (new Name(Name(generated_name).concatenate(active_origin_)));
-        previous_name_ = true;
-
-        const rdata::RdataPtr rdata =
-            rdata::createRdata(rrtype, zone_class_, generated_rdata);
-        // In case we get null, it means there was error creating the
-        // Rdata. The errors should have been reported by callbacks_
-        // already. We need to decide if we want to continue or not.
-        if (rdata) {
-            add_callback_(*last_name_, zone_class_, rrtype,
-                          getCurrentTTL(explicit_ttl, rrtype, rdata),
-                          rdata);
-            // Good, we added another one
-            ++rr_count_;
-        } else {
-            seen_error_ = true;
-            if (!many_errors_) {
-                ok_ = false;
-                complete_ = true;
-                // We don't have the exact error here, but it was
-                // reported by the error callback.
-                isc_throw(MasterLoaderError, "Invalid RR data");
-            }
-        }
-    }
-}
-
 MasterToken
 MasterLoader::MasterLoaderImpl::handleInitialToken() {
     const MasterToken& initial_token =
index 74aed22cb755dd481f3b829f0ade2df064346b93..0ad0419f29af3d1bd2852f2c0425ce50b9c1f67c 100644 (file)
@@ -303,465 +303,6 @@ TEST_F(MasterLoaderTest, origin) {
     }
 }
 
-TEST_F(MasterLoaderTest, generate) {
-    // Various forms of the directive
-    const char* generates[] = {
-        "$generate",
-        "$GENERATE",
-        "$Generate",
-        "$GeneratE",
-        "\"$GENERATE\"",
-        0
-    };
-    for (const char** generate = generates; *generate != 0; ++generate) {
-        SCOPED_TRACE(*generate);
-
-        clear();
-        const string directive = *generate;
-        const string input =
-          "$ORIGIN example.org.\n"
-          "before.example.org. 3600 IN A 192.0.2.0\n" +
-          directive + " 3-5 host$ A 192.0.2.$\n" +
-          "after.example.org. 3600 IN A 192.0.2.255\n";
-        stringstream ss(input);
-        setLoader(ss, Name("example.org."), RRClass::IN(),
-                  MasterLoader::MANY_ERRORS);
-
-        loader_->load();
-        EXPECT_TRUE(loader_->loadedSuccessfully());
-        EXPECT_TRUE(errors_.empty());
-
-        // The "before" and "after" scaffolding below checks that no
-        // extra records are added by $GENERATE outside the requested
-        // range.
-        checkRR("before.example.org", RRType::A(), "192.0.2.0");
-        checkRR("host3.example.org", RRType::A(), "192.0.2.3");
-        checkRR("host4.example.org", RRType::A(), "192.0.2.4");
-        checkRR("host5.example.org", RRType::A(), "192.0.2.5");
-        checkRR("after.example.org", RRType::A(), "192.0.2.255");
-    }
-}
-
-TEST_F(MasterLoaderTest, generateRelativeLHS) {
-    const string input =
-        "$ORIGIN example.org.\n"
-        "$GENERATE 1-2 @ 3600 NS ns$.example.org.\n";
-    stringstream ss(input);
-    setLoader(ss, Name("example.org."), RRClass::IN(),
-              MasterLoader::MANY_ERRORS);
-
-    loader_->load();
-    EXPECT_TRUE(loader_->loadedSuccessfully());
-    EXPECT_TRUE(errors_.empty());
-
-    checkRR("example.org", RRType::NS(), "ns1.example.org.");
-    checkRR("example.org", RRType::NS(), "ns2.example.org.");
-}
-
-TEST_F(MasterLoaderTest, generateInFront) {
-    // $ is in the front
-    const string input =
-        "$ORIGIN example.org.\n"
-        "$GENERATE 9-10 $host 3600 TXT \"$ pomegranate\"\n";
-    stringstream ss(input);
-    setLoader(ss, Name("example.org."), RRClass::IN(),
-              MasterLoader::MANY_ERRORS);
-
-    loader_->load();
-    EXPECT_TRUE(loader_->loadedSuccessfully());
-    EXPECT_TRUE(errors_.empty());
-
-    checkRR("9host.example.org", RRType::TXT(), "9 pomegranate");
-    checkRR("10host.example.org", RRType::TXT(), "10 pomegranate");
-}
-
-TEST_F(MasterLoaderTest, generateInMiddle) {
-    // $ is in the middle
-    const string input =
-        "$ORIGIN example.org.\n"
-        "$GENERATE 9-10 num$-host 3600 TXT \"This is $ pomegranate\"\n";
-    stringstream ss(input);
-    setLoader(ss, Name("example.org."), RRClass::IN(),
-              MasterLoader::MANY_ERRORS);
-
-    loader_->load();
-    EXPECT_TRUE(loader_->loadedSuccessfully());
-    EXPECT_TRUE(errors_.empty());
-
-    checkRR("num9-host.example.org", RRType::TXT(), "This is 9 pomegranate");
-    checkRR("num10-host.example.org", RRType::TXT(), "This is 10 pomegranate");
-}
-
-TEST_F(MasterLoaderTest, generateAtEnd) {
-    // $ is at the end
-    const string input =
-        "$ORIGIN example.org.\n"
-        "$GENERATE 9-10 num$-host 3600 TXT Pomegranate$\n";
-    stringstream ss(input);
-    setLoader(ss, Name("example.org."), RRClass::IN(),
-              MasterLoader::MANY_ERRORS);
-
-    loader_->load();
-    EXPECT_TRUE(loader_->loadedSuccessfully());
-    EXPECT_TRUE(errors_.empty());
-
-    checkRR("num9-host.example.org", RRType::TXT(), "Pomegranate9");
-    checkRR("num10-host.example.org", RRType::TXT(), "Pomegranate10");
-}
-
-TEST_F(MasterLoaderTest, generateWithDoublePlaceholder) {
-    const string input =
-        "$ORIGIN example.org.\n"
-        "$GENERATE 9-10 host$ 3600 TXT \"This is $$ pomegranate\"\n";
-    stringstream ss(input);
-    setLoader(ss, Name("example.org."), RRClass::IN(),
-              MasterLoader::MANY_ERRORS);
-
-    loader_->load();
-    EXPECT_TRUE(loader_->loadedSuccessfully());
-    EXPECT_TRUE(errors_.empty());
-
-    checkRR("host9.example.org", RRType::TXT(), "This is $ pomegranate");
-    checkRR("host10.example.org", RRType::TXT(), "This is $ pomegranate");
-}
-
-TEST_F(MasterLoaderTest, generateWithEscape) {
-    const string input =
-        "$ORIGIN example.org.\n"
-        "$GENERATE 9-10 host$ 3600 TXT \"This is \\$\\pomegranate\"\n";
-    stringstream ss(input);
-    setLoader(ss, Name("example.org."), RRClass::IN(),
-              MasterLoader::MANY_ERRORS);
-
-    loader_->load();
-    EXPECT_TRUE(loader_->loadedSuccessfully());
-    EXPECT_TRUE(errors_.empty());
-
-    checkRR("host9.example.org", RRType::TXT(), "This is \\$\\pomegranate");
-    checkRR("host10.example.org", RRType::TXT(), "This is \\$\\pomegranate");
-}
-
-TEST_F(MasterLoaderTest, generateWithParams) {
-    const string input =
-        "$ORIGIN example.org.\n"
-        "$TTL 3600\n"
-        "$GENERATE 2-3 host$ A 192.0.2.$\n"
-        "$GENERATE 5-6 host$ 3600 A 192.0.2.$\n"
-        "$GENERATE 8-9 host$ IN A 192.0.2.$\n"
-        "$GENERATE 11-12 host$ IN 3600 A 192.0.2.$\n"
-        "$GENERATE 14-15 host$ 3600 IN A 192.0.2.$\n";
-    stringstream ss(input);
-    setLoader(ss, Name("example.org."), RRClass::IN(),
-              MasterLoader::MANY_ERRORS);
-
-    loader_->load();
-    EXPECT_TRUE(loader_->loadedSuccessfully());
-    EXPECT_TRUE(errors_.empty());
-
-    checkRR("host2.example.org", RRType::A(), "192.0.2.2");
-    checkRR("host3.example.org", RRType::A(), "192.0.2.3");
-
-    checkRR("host5.example.org", RRType::A(), "192.0.2.5");
-    checkRR("host6.example.org", RRType::A(), "192.0.2.6");
-
-    checkRR("host8.example.org", RRType::A(), "192.0.2.8");
-    checkRR("host9.example.org", RRType::A(), "192.0.2.9");
-
-    checkRR("host11.example.org", RRType::A(), "192.0.2.11");
-    checkRR("host12.example.org", RRType::A(), "192.0.2.12");
-
-    checkRR("host14.example.org", RRType::A(), "192.0.2.14");
-    checkRR("host15.example.org", RRType::A(), "192.0.2.15");
-}
-
-TEST_F(MasterLoaderTest, generateWithStep) {
-    const string input =
-        "$ORIGIN example.org.\n"
-        "$GENERATE 2-9/2 host$ 3600 A 192.0.2.$\n"
-        "$GENERATE 12-21/3 host$ 3600 A 192.0.2.$\n"
-        "$GENERATE 30-31/1 host$ 3600 A 192.0.2.$\n";
-    stringstream ss(input);
-    setLoader(ss, Name("example.org."), RRClass::IN(),
-              MasterLoader::MANY_ERRORS);
-
-    loader_->load();
-    EXPECT_TRUE(loader_->loadedSuccessfully());
-    EXPECT_TRUE(errors_.empty());
-
-    checkRR("host2.example.org", RRType::A(), "192.0.2.2");
-    checkRR("host4.example.org", RRType::A(), "192.0.2.4");
-    checkRR("host6.example.org", RRType::A(), "192.0.2.6");
-    checkRR("host8.example.org", RRType::A(), "192.0.2.8");
-
-    checkRR("host12.example.org", RRType::A(), "192.0.2.12");
-    checkRR("host15.example.org", RRType::A(), "192.0.2.15");
-    checkRR("host18.example.org", RRType::A(), "192.0.2.18");
-    checkRR("host21.example.org", RRType::A(), "192.0.2.21");
-
-    checkRR("host30.example.org", RRType::A(), "192.0.2.30");
-    checkRR("host31.example.org", RRType::A(), "192.0.2.31");
-}
-
-TEST_F(MasterLoaderTest, generateWithModifiers) {
-    const string input =
-        "$ORIGIN example.org.\n"
-        "$TTL 3600\n"
-
-        // Use a positive delta of 1 in the LHS and a negative delta of
-        // -1 in the RHS
-        "$GENERATE 2-9/2 host${1} A 192.0.2.${-1}\n"
-
-        "$GENERATE 10-12 host${0,4} A 192.0.2.$\n"
-        "$GENERATE 14-15 host${0,4,d} A 192.0.2.$\n"
-
-        // Names are case-insensitive, so we use TXT's RDATA to check
-        // case with hex representation.
-        "$GENERATE 30-31 host$ TXT \"Value ${0,4,x}\"\n"
-        "$GENERATE 42-43 host$ TXT \"Value ${0,4,X}\"\n"
-
-        // Octal does not use any alphabets
-        "$GENERATE 45-46 host${0,4,o} A 192.0.2.$\n"
-
-        // Here, the LHS has a trailing dot (which would result in an
-        // out-of-zone name), but that should be handled as a relative
-        // name.
-        "$GENERATE 90-92 ${0,8,n} A 192.0.2.$\n"
-
-        // Here, the LHS has no trailing dot, and results in the same
-        // number of labels as width=8 above.
-        "$GENERATE 94-96 ${0,7,n} A 192.0.2.$\n"
-
-        // Names are case-insensitive, so we use TXT's RDATA to check
-        // case with nibble representation.
-        "$GENERATE 106-107 host$ TXT \"Value ${0,9,n}\"\n"
-        "$GENERATE 109-110 host$ TXT \"Value ${0,9,N}\"\n"
-
-        // Junk type will not parse and 'd' is assumed. No error is
-        // generated (this is to match BIND 9 behavior).
-        "$GENERATE 200-201 host${0,4,j} A 192.0.2.$\n";
-    stringstream ss(input);
-    setLoader(ss, Name("example.org."), RRClass::IN(),
-              MasterLoader::MANY_ERRORS);
-
-    loader_->load();
-    EXPECT_TRUE(loader_->loadedSuccessfully());
-    EXPECT_TRUE(errors_.empty());
-
-    checkRR("host3.example.org", RRType::A(), "192.0.2.1");
-    checkRR("host5.example.org", RRType::A(), "192.0.2.3");
-    checkRR("host7.example.org", RRType::A(), "192.0.2.5");
-    checkRR("host9.example.org", RRType::A(), "192.0.2.7");
-
-    checkRR("host0010.example.org", RRType::A(), "192.0.2.10");
-    checkRR("host0011.example.org", RRType::A(), "192.0.2.11");
-    checkRR("host0012.example.org", RRType::A(), "192.0.2.12");
-
-    checkRR("host0014.example.org", RRType::A(), "192.0.2.14");
-    checkRR("host0015.example.org", RRType::A(), "192.0.2.15");
-
-    checkRR("host30.example.org", RRType::TXT(), "Value 001e");
-    checkRR("host31.example.org", RRType::TXT(), "Value 001f");
-
-    checkRR("host42.example.org", RRType::TXT(), "Value 002A");
-    checkRR("host43.example.org", RRType::TXT(), "Value 002B");
-
-    checkRR("host0055.example.org", RRType::A(), "192.0.2.45");
-    checkRR("host0056.example.org", RRType::A(), "192.0.2.46");
-
-    checkRR("a.5.0.0.example.org", RRType::A(), "192.0.2.90");
-    checkRR("b.5.0.0.example.org", RRType::A(), "192.0.2.91");
-    checkRR("c.5.0.0.example.org", RRType::A(), "192.0.2.92");
-
-    checkRR("e.5.0.0.example.org", RRType::A(), "192.0.2.94");
-    checkRR("f.5.0.0.example.org", RRType::A(), "192.0.2.95");
-    checkRR("0.6.0.0.example.org", RRType::A(), "192.0.2.96");
-
-    checkRR("host106.example.org", RRType::TXT(), "Value a.6.0.0.0");
-    checkRR("host107.example.org", RRType::TXT(), "Value b.6.0.0.0");
-    checkRR("host109.example.org", RRType::TXT(), "Value D.6.0.0.0");
-    checkRR("host110.example.org", RRType::TXT(), "Value E.6.0.0.0");
-
-    checkRR("host0200.example.org", RRType::A(), "192.0.2.200");
-    checkRR("host0201.example.org", RRType::A(), "192.0.2.201");
-}
-
-TEST_F(MasterLoaderTest, generateWithNoModifiers) {
-    const string input =
-        "$ORIGIN example.org.\n"
-        "$TTL 3600\n"
-        "$GENERATE 10-12 host${} A 192.0.2.$\n";
-    stringstream ss(input);
-    setLoader(ss, Name("example.org."), RRClass::IN(),
-              MasterLoader::MANY_ERRORS);
-
-    loader_->load();
-    EXPECT_FALSE(loader_->loadedSuccessfully());
-    ASSERT_EQ(2, errors_.size()); // For the broken GENERATE
-    EXPECT_TRUE(warnings_.empty());
-
-    checkCallbackMessage(errors_.at(0),
-                         "Invalid $GENERATE format modifiers", 3);
-    checkCallbackMessage(errors_.at(1),
-                         "$GENERATE error", 3);
-}
-
-TEST_F(MasterLoaderTest, generateWithBadModifiers) {
-    const string input =
-        "$ORIGIN example.org.\n"
-        "$TTL 3600\n"
-        "$GENERATE 10-12 host${GARBAGE} A 192.0.2.$\n";
-    stringstream ss(input);
-    setLoader(ss, Name("example.org."), RRClass::IN(),
-              MasterLoader::MANY_ERRORS);
-
-    loader_->load();
-    EXPECT_FALSE(loader_->loadedSuccessfully());
-    ASSERT_EQ(2, errors_.size()); // For the broken GENERATE
-    EXPECT_TRUE(warnings_.empty());
-
-    checkCallbackMessage(errors_.at(0),
-                         "Invalid $GENERATE format modifiers", 3);
-    checkCallbackMessage(errors_.at(1),
-                         "$GENERATE error", 3);
-}
-
-TEST_F(MasterLoaderTest, generateMissingRange) {
-    const string input =
-        "$ORIGIN example.org.\n"
-        "$GENERATE\n";
-    stringstream ss(input);
-    setLoader(ss, Name("example.org."), RRClass::IN(),
-              MasterLoader::MANY_ERRORS);
-
-    loader_->load();
-    EXPECT_FALSE(loader_->loadedSuccessfully());
-    EXPECT_EQ(1, errors_.size()); // For the broken GENERATE
-    EXPECT_TRUE(warnings_.empty());
-
-    checkCallbackMessage(errors_.at(0),
-                         "unexpected end of input", 2);
-}
-
-TEST_F(MasterLoaderTest, generateMissingLHS) {
-    const string input =
-        "$ORIGIN example.org.\n"
-        "$GENERATE 2-4\n";
-    stringstream ss(input);
-    setLoader(ss, Name("example.org."), RRClass::IN(),
-              MasterLoader::MANY_ERRORS);
-
-    loader_->load();
-    EXPECT_FALSE(loader_->loadedSuccessfully());
-    EXPECT_EQ(1, errors_.size()); // For the broken GENERATE
-    EXPECT_TRUE(warnings_.empty());
-
-    checkCallbackMessage(errors_.at(0),
-                         "unexpected end of input", 2);
-}
-
-TEST_F(MasterLoaderTest, generateMissingType) {
-    const string input =
-        "$ORIGIN example.org.\n"
-        "$GENERATE 2-4 host$\n";
-    stringstream ss(input);
-    setLoader(ss, Name("example.org."), RRClass::IN(),
-              MasterLoader::MANY_ERRORS);
-
-    loader_->load();
-    EXPECT_FALSE(loader_->loadedSuccessfully());
-    EXPECT_EQ(1, errors_.size()); // For the broken GENERATE
-    EXPECT_TRUE(warnings_.empty());
-
-    checkCallbackMessage(errors_.at(0),
-                         "unexpected end of input", 2);
-}
-
-TEST_F(MasterLoaderTest, generateMissingRHS) {
-    const string input =
-        "$ORIGIN example.org.\n"
-        "$GENERATE 2-4 host$ A\n";
-    stringstream ss(input);
-    setLoader(ss, Name("example.org."), RRClass::IN(),
-              MasterLoader::MANY_ERRORS);
-
-    loader_->load();
-    EXPECT_FALSE(loader_->loadedSuccessfully());
-    EXPECT_EQ(1, errors_.size()); // For the broken GENERATE
-    EXPECT_TRUE(warnings_.empty());
-
-    checkCallbackMessage(errors_.at(0),
-                         "unexpected end of input", 2);
-}
-
-TEST_F(MasterLoaderTest, generateWithBadRangeSyntax) {
-    const string input =
-        "$ORIGIN example.org.\n"
-        "$GENERATE ABCD host$ 3600 A 192.0.2.$\n";
-    stringstream ss(input);
-    setLoader(ss, Name("example.org."), RRClass::IN(),
-              MasterLoader::MANY_ERRORS);
-
-    loader_->load();
-    EXPECT_FALSE(loader_->loadedSuccessfully());
-    EXPECT_EQ(1, errors_.size()); // For the broken GENERATE
-    EXPECT_TRUE(warnings_.empty());
-
-    checkCallbackMessage(errors_.at(0),
-                         "$GENERATE: invalid range: ABCD", 2);
-}
-
-TEST_F(MasterLoaderTest, generateWithInvalidRange) {
-    // start > stop
-    const string input =
-        "$ORIGIN example.org.\n"
-        "$GENERATE 2-1 host$ 3600 A 192.0.2.$\n";
-    stringstream ss(input);
-    setLoader(ss, Name("example.org."), RRClass::IN(),
-              MasterLoader::MANY_ERRORS);
-
-    loader_->load();
-    EXPECT_FALSE(loader_->loadedSuccessfully());
-    EXPECT_EQ(1, errors_.size()); // For the broken GENERATE
-    EXPECT_TRUE(warnings_.empty());
-
-    checkCallbackMessage(errors_.at(0),
-                         "$GENERATE: invalid range: 2-1", 2);
-}
-
-TEST_F(MasterLoaderTest, generateWithInvalidClass) {
-    const string input =
-        "$ORIGIN example.org.\n"
-        "$GENERATE 1-2 host$ 3600 CH A 192.0.2.$\n";
-    stringstream ss(input);
-    setLoader(ss, Name("example.org."), RRClass::IN(),
-              MasterLoader::MANY_ERRORS);
-
-    loader_->load();
-    EXPECT_FALSE(loader_->loadedSuccessfully());
-    EXPECT_EQ(1, errors_.size()); // For the broken GENERATE
-    EXPECT_TRUE(warnings_.empty());
-
-    checkCallbackMessage(errors_.at(0),
-                         "Class mismatch: CH vs. IN", 2);
-}
-
-TEST_F(MasterLoaderTest, generateWithNoAvailableTTL) {
-    const string input =
-        "$ORIGIN example.org.\n"
-        "$GENERATE 1-2 host$ A 192.0.2.$\n";
-    stringstream ss(input);
-    setLoader(ss, Name("example.org."), RRClass::IN(),
-              MasterLoader::MANY_ERRORS);
-
-    loader_->load();
-    EXPECT_FALSE(loader_->loadedSuccessfully());
-    EXPECT_EQ(1, errors_.size()); // For the broken GENERATE
-    EXPECT_TRUE(warnings_.empty());
-
-    checkCallbackMessage(errors_.at(0),
-                         "no TTL specified; load rejected", 2);
-}
-
 // Test the source is correctly popped even after error
 TEST_F(MasterLoaderTest, popAfterError) {
     const string include_str = "$include " TEST_DATA_SRCDIR