Source code
Revision control
Copy as Markdown
Other Tools
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
#include <stdlib.h>
#include <string.h>
#include "gtest/gtest.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/dom/nsCSPContext.h"
#include "mozilla/gtest/MozAssertions.h"
#include "nsComponentManagerUtils.h"
#include "nsIContentSecurityPolicy.h"
#include "nsIPrefBranch.h"
#include "nsIPrefService.h"
#include "nsNetUtil.h"
#include "nsStringFwd.h"
/*
 * Testing the parser is non trivial, especially since we can not call
 * parser functionality directly in compiled code tests.
 * All the tests (except the fuzzy tests at the end) follow the same schemata:
 *   a) create an nsIContentSecurityPolicy object
 *   b) set the selfURI in SetRequestContextWithPrincipal
 *   c) append one or more policies by calling AppendPolicy
 *   d) check if the policy count is correct by calling GetPolicyCount
 *   e) compare the result of the policy with the expected output
 *      using the struct PolicyTest;
 *
 * In general we test:
 * a) policies that the parser should accept
 * b) policies that the parser should reject
 * c) policies that are randomly generated (fuzzy tests)
 *
 * Please note that fuzzy tests are *DISABLED* by default and shold only
 * be run *OFFLINE* whenever code in nsCSPParser changes.
 * To run fuzzy tests, flip RUN_OFFLINE_TESTS to 1.
 *
 */
#define RUN_OFFLINE_TESTS 0
/*
 * Offline tests are separated in three different groups:
 *  * TestFuzzyPolicies - complete random ASCII input
 *  * TestFuzzyPoliciesIncDir - a directory name followed by random ASCII
 *  * TestFuzzyPoliciesIncDirLimASCII - a directory name followed by limited
 * ASCII which represents more likely user input.
 *
 *  We run each of this categories |kFuzzyRuns| times.
 */
#if RUN_OFFLINE_TESTS
static const uint32_t kFuzzyRuns = 10000;
#endif
// For fuzzy testing we actually do not care about the output,
// we just want to make sure that the parser can handle random
// input, therefore we use kFuzzyExpectedPolicyCount to return early.
static const uint32_t kFuzzyExpectedPolicyCount = 111;
static const uint32_t kMaxPolicyLength = 96;
struct PolicyTest {
  char policy[kMaxPolicyLength];
  char expectedResult[kMaxPolicyLength];
};
nsresult runTest(
    uint32_t aExpectedPolicyCount,  // this should be 0 for policies which
                                    // should fail to parse
    const char* aPolicy, const char* aExpectedResult) {
  nsresult rv;
  nsCOMPtr<nsIURI> selfURI;
  NS_ENSURE_SUCCESS(rv, rv);
  nsCOMPtr<nsIPrincipal> selfURIPrincipal;
  mozilla::OriginAttributes attrs;
  selfURIPrincipal =
      mozilla::BasePrincipal::CreateContentPrincipal(selfURI, attrs);
  NS_ENSURE_TRUE(selfURIPrincipal, NS_ERROR_FAILURE);
  // create a CSP object
  nsCOMPtr<nsIContentSecurityPolicy> csp =
      do_CreateInstance(NS_CSPCONTEXT_CONTRACTID, &rv);
  NS_ENSURE_SUCCESS(rv, rv);
  // for testing the parser we only need to set a principal which is needed
  // to translate the keyword 'self' into an actual URI.
  rv = csp->SetRequestContextWithPrincipal(selfURIPrincipal, selfURI, ""_ns, 0);
  NS_ENSURE_SUCCESS(rv, rv);
  // append a policy
  nsString policyStr;
  policyStr.AssignASCII(aPolicy);
  rv = csp->AppendPolicy(policyStr, false, false);
  NS_ENSURE_SUCCESS(rv, rv);
  // when executing fuzzy tests we do not care about the actual output
  // of the parser, we just want to make sure that the parser is not crashing.
  if (aExpectedPolicyCount == kFuzzyExpectedPolicyCount) {
    return NS_OK;
  }
  // verify that the expected number of policies exists
  uint32_t actualPolicyCount;
  rv = csp->GetPolicyCount(&actualPolicyCount);
  NS_ENSURE_SUCCESS(rv, rv);
  if (actualPolicyCount != aExpectedPolicyCount) {
    EXPECT_TRUE(false)
        << "Actual policy count not equal to expected policy count ("
        << actualPolicyCount << " != " << aExpectedPolicyCount
        << ") for policy: " << aPolicy;
    return NS_ERROR_UNEXPECTED;
  }
  // if the expected policy count is 0, we can return, because
  // we can not compare any output anyway. Used when parsing
  // errornous policies.
  if (aExpectedPolicyCount == 0) {
    return NS_OK;
  }
  // compare the parsed policy against the expected result
  nsString parsedPolicyStr;
  // checking policy at index 0, which is the one what we appended.
  rv = csp->GetPolicyString(0, parsedPolicyStr);
  NS_ENSURE_SUCCESS(rv, rv);
  if (!NS_ConvertUTF16toUTF8(parsedPolicyStr).EqualsASCII(aExpectedResult)) {
    EXPECT_TRUE(false) << "Actual policy does not match expected policy ("
                       << NS_ConvertUTF16toUTF8(parsedPolicyStr).get()
                       << " != " << aExpectedResult << ")";
    return NS_ERROR_UNEXPECTED;
  }
  return NS_OK;
}
// ============================= run Tests ========================
nsresult runTestSuite(const PolicyTest* aPolicies, uint32_t aPolicyCount,
                      uint32_t aExpectedPolicyCount) {
  nsresult rv;
  nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
  // Add prefs you need to set to parse CSP here, see comments for example
  // bool examplePref = false;
  bool trustedTypesEnabled = false;
  constexpr auto kTrustedTypesEnabledPrefName =
      "dom.security.trusted_types.enabled";
  if (prefs) {
    // prefs->GetBoolPref("security.csp.examplePref", &examplePref);
    // prefs->SetBoolPref("security.csp.examplePref", true);
    prefs->GetBoolPref(kTrustedTypesEnabledPrefName, &trustedTypesEnabled);
    prefs->SetBoolPref(kTrustedTypesEnabledPrefName, true);
  }
  for (uint32_t i = 0; i < aPolicyCount; i++) {
    rv = runTest(aExpectedPolicyCount, aPolicies[i].policy,
                 aPolicies[i].expectedResult);
    NS_ENSURE_SUCCESS(rv, rv);
  }
  if (prefs) {
    // prefs->SetBoolPref("security.csp.examplePref", examplePref);
    prefs->SetBoolPref(kTrustedTypesEnabledPrefName, trustedTypesEnabled);
  }
  return NS_OK;
}
// ============================= TestDirectives ========================
TEST(CSPParser, Directives)
{
  static const PolicyTest policies[] = {
      // clang-format off
    { "connect-src xn--mnchen-3ya.de",
    { "script-src 'nonce-correctscriptnonce'",
      "script-src 'nonce-correctscriptnonce'" },
    { "script-src 'nonce-a'",
      "script-src 'nonce-a'" },
    { "script-src 'sha256-a'",
      "script-src 'sha256-a'" },
    { "script-src 'sha256-siVR8vAcqP06h2ppeNwqgjr0yZ6yned4X2VF84j4GmI='",
      "script-src 'sha256-siVR8vAcqP06h2ppeNwqgjr0yZ6yned4X2VF84j4GmI='" },
    { "script-src 'nonce-foo' 'unsafe-inline' ",
      "script-src 'nonce-foo' 'unsafe-inline'" },
    { "script-src 'nonce-foo' 'strict-dynamic' 'unsafe-inline' https:  ",
      "script-src 'nonce-foo' 'strict-dynamic' 'unsafe-inline' https:" },
    { "script-src 'nonce-foo' 'strict-dynamic' 'unsafe-inline' 'report-sample' https:  ",
      "script-src 'nonce-foo' 'strict-dynamic' 'unsafe-inline' 'report-sample' https:" },
    { "default-src 'sha256-siVR8' 'strict-dynamic' 'unsafe-inline' https:  ",
      "default-src 'sha256-siVR8' 'strict-dynamic' 'unsafe-inline' https:" },
    { "require-trusted-types-for 'script'",
      "require-trusted-types-for 'script'" },
    { "require-trusted-types-for 'script' invalid",
    { "require-trusted-types-for 'script' 'invalid'",
    { "trusted-types somePolicyName", "trusted-types somePolicyName" },
    { "trusted-types somePolicyName anotherPolicyName 1 - # = _ / @ . % *",
      "trusted-types somePolicyName anotherPolicyName 1 - # = _ / @ . % *" },
      // clang-format on
  };
  uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
  ASSERT_NS_SUCCEEDED(runTestSuite(policies, policyCount, 1));
}
// ============================= TestKeywords ========================
TEST(CSPParser, Keywords)
{
  static const PolicyTest policies[] = {
      // clang-format off
    { "script-src 'self'",
      "script-src 'self'" },
    { "script-src 'unsafe-inline'",
      "script-src 'unsafe-inline'" },
    { "script-src 'unsafe-eval'",
      "script-src 'unsafe-eval'" },
    { "script-src 'unsafe-inline' 'unsafe-eval'",
      "script-src 'unsafe-inline' 'unsafe-eval'" },
    { "script-src 'none'",
      "script-src 'none'" },
    { "script-src 'wasm-unsafe-eval'",
      "script-src 'wasm-unsafe-eval'" },
    { "img-src 'none'; script-src 'unsafe-eval' 'unsafe-inline'; default-src 'self'",
      "img-src 'none'; script-src 'unsafe-eval' 'unsafe-inline'; default-src 'self'" },
    { "trusted-types somePolicyName 'allow-duplicates'",
      "trusted-types somePolicyName 'allow-duplicates'" },
    { "trusted-types 'none'", "trusted-types 'none'" },
    { "trusted-types", "trusted-types 'none'" },
    { "trusted-types 'none' somePolicyName", "trusted-types somePolicyName" },
    { "trusted-types 'none' 'none'", "trusted-types 'none'" },
    { "trusted-types 'none' 'allow-duplicates'", "trusted-types 'allow-duplicates'" },
    { "trusted-types 'none' *", "trusted-types *" },
    { "trusted-types *", "trusted-types *" },
      // clang-format on
  };
  uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
  ASSERT_NS_SUCCEEDED(runTestSuite(policies, policyCount, 1));
}
// =================== TestIgnoreUpperLowerCasePolicies ==============
TEST(CSPParser, IgnoreUpperLowerCasePolicies)
{
  static const PolicyTest policies[] = {
      // clang-format off
    { "script-src 'SELF'",
      "script-src 'self'" },
    { "sCriPt-src 'Unsafe-Inline'",
      "script-src 'unsafe-inline'" },
    { "SCRIPT-src 'unsafe-eval'",
      "script-src 'unsafe-eval'" },
    { "default-SRC 'unsafe-inline' 'unsafe-eval'",
      "default-src 'unsafe-inline' 'unsafe-eval'" },
    { "script-src 'NoNe'",
      "script-src 'none'" },
    { "img-sRc 'noNe'; scrIpt-src 'unsafe-EVAL' 'UNSAFE-inline'; deFAULT-src 'Self'",
      "img-src 'none'; script-src 'unsafe-eval' 'unsafe-inline'; default-src 'self'" },
    { "script-src 'none' test.com;",
    { "script-src 'NoNCE-correctscriptnonce'",
      "script-src 'nonce-correctscriptnonce'" },
    { "script-src 'NoncE-NONCENEEDSTOBEUPPERCASE'",
      "script-src 'nonce-NONCENEEDSTOBEUPPERCASE'" },
    { "script-src 'SHA256-siVR8vAcqP06h2ppeNwqgjr0yZ6yned4X2VF84j4GmI='",
      "script-src 'sha256-siVR8vAcqP06h2ppeNwqgjr0yZ6yned4X2VF84j4GmI='" },
    { "upgrade-INSECURE-requests",
      "upgrade-insecure-requests" },
    { "sanDBox alloW-foRMs",
      "sandbox allow-forms"},
      // clang-format on
  };
  uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
  ASSERT_NS_SUCCEEDED(runTestSuite(policies, policyCount, 1));
}
// ========================= TestPaths ===============================
TEST(CSPParser, Paths)
{
  static const PolicyTest policies[] = {
      // clang-format off
    { "report-uri /examplepath",
  };
  uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
  ASSERT_NS_SUCCEEDED(runTestSuite(policies, policyCount, 1));
}
// ======================== TestSimplePolicies =======================
TEST(CSPParser, SimplePolicies)
{
  static const PolicyTest policies[] = {
      // clang-format off
    { "frame-src intent:",
      "frame-src intent:" },
    { "default-src *",
      "default-src *" },
    { "default-src https:",
      "default-src https:" },
    { "default-src *:*",
    { "default-src *:80",
    { "default-src javascript:",
      "default-src javascript:" },
    { "default-src data:",
      "default-src data:" },
    { "object-src 'self'",
      "object-src 'self'" },
    { "connect-src example.com *.other.com",
    { "style-src *.other.com example.com",
    { "default-src 'self'; img-src *;",
      "default-src 'self'; img-src *" },
    { "object-src media1.example.com media2.example.com *.cdn.example.com;",
    { "script-src trustedscripts.example.com",
    { "script-src 'self' ; default-src trustedscripts.example.com",
    { "   ;   default-src abc",
    { " ; ; ; ;     default-src            abc    ; ; ; ;",
    { "script-src 'none' 'none' 'none';",
      "script-src 'none'" },
    { "default-src 127.0.0.1",
    { "default-src 127.0.0.1:*",
    { "default-src -; ",
    { "script-src 1",
    { "upgrade-insecure-requests",
      "upgrade-insecure-requests" },
    { "upgrade-insecure-requests https:",
      "upgrade-insecure-requests" },
    { "sandbox allow-scripts allow-forms  ",
      "sandbox allow-scripts allow-forms" },
      // clang-format on
  };
  uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
  ASSERT_NS_SUCCEEDED(runTestSuite(policies, policyCount, 1));
}
// =================== TestPoliciesWithInvalidSrc ====================
TEST(CSPParser, PoliciesWithInvalidSrc)
{
  static const PolicyTest policies[] = {
      // clang-format off
      "script-src 'self'" },
    { "script-src 'none' test.com; script-src example.com",
    { "default-src **",
      "default-src 'none'" },
    { "default-src 'self",
      "default-src 'none'" },
    { "default-src 'unsafe-inlin' ",
      "default-src 'none'" },
    { "default-src */",
      "default-src 'none'" },
    { "default-src",
      "default-src 'none'" },
    { "default-src 'unsafe-inlin' ",
      "default-src 'none'" },
    { "default-src :88",
      "default-src 'none'" },
    { "script-src abc::::::88",
      "script-src 'none'" },
    { "script-src *.*:*",
      "script-src 'none'" },
    { "img-src *::88",
      "img-src 'none'" },
      "object-src 'none'" },
    { "script-src test..com",
      "script-src 'none'" },
    { "script-src sub1.sub2.example+",
      "script-src 'none'" },
      "script-src 'none'" },
      "script-src 'none'" },
      "script-src 'none'" },
      "script-src 'none'" },
      "script-src 'none'" },
      "script-src 'none'" },
      "script-src 'none'" },
      "script-src 'none'" },
    { "script-src 'nonce-{invalid}'",
      "script-src 'none'" },
    { "script-src 'sha256-{invalid}'",
      "script-src 'none'" },
    { "script-src 'nonce-in$valid'",
      "script-src 'none'" },
    { "script-src 'sha256-in$valid'",
      "script-src 'none'" },
    { "script-src 'nonce-invalid==='",
      "script-src 'none'" },
    { "script-src 'sha256-invalid==='",
      "script-src 'none'" },
    { "script-src 'nonce-==='",
      "script-src 'none'" },
    { "script-src 'sha256-==='",
      "script-src 'none'" },
    { "script-src 'nonce-=='",
      "script-src 'none'" },
    { "script-src 'sha256-=='",
      "script-src 'none'" },
    { "script-src 'nonce-='",
      "script-src 'none'" },
    { "script-src 'sha256-='",
      "script-src 'none'" },
    { "script-src 'nonce-'",
      "script-src 'none'" },
    { "script-src 'sha256-'",
      "script-src 'none'" },
      "connect-src 'none'" },
      "script-src 'none'" },
    { "sandbox    foo",
      "sandbox"},
      // clang-format on
  };
  // amount of tests - 1, because the latest should be ignored.
  uint32_t policyCount = (sizeof(policies) / sizeof(PolicyTest)) - 1;
  ASSERT_NS_SUCCEEDED(runTestSuite(policies, policyCount, 1));
}
// ============================= TestBadPolicies =======================
TEST(CSPParser, BadPolicies)
{
  static const PolicyTest policies[] = {
      // clang-format off
    { "script-sr 'self", "" },
    { "", "" },
    { "; ; ; ; ; ; ;", "" },
    { "defaut-src asdf", "" },
    { "default-src: aaa", "" },
    { "report-uri", ""},
    { "require-sri-for", ""},
    { "require-sri-for style", ""},
    { "require-trusted-types-for invalid" },
    { "require-trusted-types-for 'invalid'" },
      // clang-format on
  };
  uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
  ASSERT_NS_SUCCEEDED(runTestSuite(policies, policyCount, 0));
}
// ======================= TestGoodGeneratedPolicies =================
TEST(CSPParser, GoodGeneratedPolicies)
{
  static const PolicyTest policies[] = {
      // clang-format off
    { "default-src 'self'; img-src *",
      "default-src 'self'; img-src *" },
    { "report-uri /policy",
    { "img-src *",
      "img-src *" },
    { "media-src foo.bar",
    { "frame-src *.bar",
    { "font-src com",
    { "connect-src f00b4r.com",
    { "script-src *.a.b.c",
    { "object-src *.b.c",
    { "style-src a.b.c",
    { "img-src a.com",
    { "frame-src a2-c.com",
    { "connect-src *.a.com",
    { "default-src a.com:23",
    { "object-src data:",
      "object-src data:" },
    { "style-src javascript:",
      "style-src javascript:" },
    { "style-src 'none'",
      "style-src 'none'" },
    { "script-src *.foo.com",
    { "default-src *",
      "default-src *" },
    { "img-src bar.com:*",
    { "default-src 'none'",
      "default-src 'none'" },
    { "report-uri /report.py",
    { "media-src foo/bar/report.py",
    { "report-uri /",
    { "media-src bar.com",
    { "script-src 'self'",
      "script-src 'self'" },
    { "img-src HTTP",
    { "media-src http",
    { "frame-src 'SELF'",
      "frame-src 'self'" },
    { "DEFAULT-src 'self';",
      "default-src 'self'" },
    { "default-src 'NONE'",
      "default-src 'none'" },
    { "script-src policy-uri ",
    { "img-src 'self'; ",
      "img-src 'self'" },
    { "frame-ancestors foo-bar.com",
    { "frame-ancestors 'self'",
      "frame-ancestors 'self'" },
      "frame-ancestors 'none'" },
    { "default-src 'none'; frame-ancestors 'self'",
      "default-src 'none'; frame-ancestors 'self'" },
    { "default-src 'self'; frame-ancestors 'self'",
      "default-src 'self'; frame-ancestors 'self'" },
      // clang-format on
  };
  uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
  ASSERT_NS_SUCCEEDED(runTestSuite(policies, policyCount, 1));
}
// ==================== TestBadGeneratedPolicies ====================
TEST(CSPParser, BadGeneratedPolicies)
{
  static const PolicyTest policies[] = {
      // clang-format off
    { "foo.*.bar", ""},
    { "foo!bar.com", ""},
    { "x.*.a.com", ""},
    { "a#2-c.com", ""},
    { "f!oo.bar", ""},
    { "**", ""},
    { "*a", ""},
      // clang-format on
  };
  uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
  ASSERT_NS_SUCCEEDED(runTestSuite(policies, policyCount, 0));
}
// ============ TestGoodGeneratedPoliciesForPathHandling =============
TEST(CSPParser, GoodGeneratedPoliciesForPathHandling)
{
  // lands we have to update the expected output to include the parsed path
  static const PolicyTest policies[] = {
      // clang-format off
    { "img-src test1.example.com",
    { "img-src test1.example.com/",
    { "img-src test1.example.com/path-1",
    { "img-src test1.example.com/path-1/",
    { "img-src test1.example.com/path-1/path_2/",
    { "img-src test1.example.com/path-1/path_2/file.js",
    { "img-src test1.example.com/path-1/path_2/file_1.js",
    { "img-src test1.example.com/path-1/path_2/file-2.js",
    { "img-src test1.example.com/path-1/path_2/f.js",
    { "img-src test1.example.com/path-1/path_2/f.oo.js",
    { "img-src *.example.com",
    { "img-src *.example.com/",
    { "img-src *.example.com/path-1",
    { "img-src *.example.com/path-1/",
    { "img-src *.example.com/path-1/path_2/",
    { "img-src *.example.com/path-1/path_2/file.js",
    { "img-src *.example.com/path-1/path_2/file_1.js",
    { "img-src *.example.com/path-1/path_2/file-2.js",
    { "img-src *.example.com/path-1/path_2/f.js",
    { "img-src *.example.com/path-1/path_2/f.oo.js",
    { "img-src test1.example.com:80",
    { "img-src test1.example.com:80/",
    { "img-src test1.example.com:80/path-1",
    { "img-src test1.example.com:80/path-1/",
    { "img-src test1.example.com:80/path-1/path_2",
    { "img-src test1.example.com:80/path-1/path_2/",
    { "img-src test1.example.com:80/path-1/path_2/file.js",
    { "img-src test1.example.com:80/path-1/path_2/f.ile.js",
    { "img-src test1.example.com:*",
    { "img-src test1.example.com:*/",
    { "img-src test1.example.com:*/path-1",
    { "img-src test1.example.com:*/path-1/",
    { "img-src test1.example.com:*/path-1/path_2",
    { "img-src test1.example.com:*/path-1/path_2/",
    { "img-src test1.example.com:*/path-1/path_2/file.js",
    { "img-src test1.example.com:*/path-1/path_2/f.ile.js",
      // clang-format on
  };
  uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
  ASSERT_NS_SUCCEEDED(runTestSuite(policies, policyCount, 1));
}
// ============== TestBadGeneratedPoliciesForPathHandling ============
TEST(CSPParser, BadGeneratedPoliciesForPathHandling)
{
  static const PolicyTest policies[] = {
      // clang-format off
    { "img-src test1.example.com:88path-1/",
      "img-src 'none'" },
    { "img-src test1.example.com:80.js",
      "img-src 'none'" },
    { "img-src test1.example.com:*.js",
      "img-src 'none'" },
    { "img-src test1.example.com:*.",
      "img-src 'none'" },
      "img-src 'none'" },
      "img-src 'none'" },
      "img-src 'none'" },
      // clang-format on
  };
  uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
  ASSERT_NS_SUCCEEDED(runTestSuite(policies, policyCount, 1));
}
// ======================== TestFuzzyPolicies ========================
// Use a policy, eliminate one character at a time,
// and feed it as input to the parser.
TEST(CSPParser, ShorteningPolicies)
{
  char pol[] =
      "'unsafe-inline' 'none'";
  uint32_t len = static_cast<uint32_t>(sizeof(pol));
  PolicyTest testPol[1];
  memset(&testPol[0].policy, '\0', kMaxPolicyLength * sizeof(char));
  while (--len) {
    memset(&testPol[0].policy, '\0', kMaxPolicyLength * sizeof(char));
    memcpy(&testPol[0].policy, &pol, len * sizeof(char));
    ASSERT_TRUE(
        NS_SUCCEEDED(runTestSuite(testPol, 1, kFuzzyExpectedPolicyCount)));
  }
}
// ============================= TestFuzzyPolicies ===================
// We generate kFuzzyRuns inputs by (pseudo) randomly picking from the 128
// ASCII characters; feed them to the parser and verfy that the parser
// handles the input gracefully.
//
// Please note, that by using srand(0) we get deterministic results!
#if RUN_OFFLINE_TESTS
TEST(CSPParser, FuzzyPolicies)
{
  // init srand with 0 so we get same results
  srand(0);
  PolicyTest testPol[1];
  memset(&testPol[0].policy, '\0', kMaxPolicyLength);
  for (uint32_t index = 0; index < kFuzzyRuns; index++) {
    // randomly select the length of the next policy
    uint32_t polLength = rand() % kMaxPolicyLength;
    // reset memory of the policy string
    memset(&testPol[0].policy, '\0', kMaxPolicyLength * sizeof(char));
    for (uint32_t i = 0; i < polLength; i++) {
      // fill the policy array with random ASCII chars
      testPol[0].policy[i] = static_cast<char>(rand() % 128);
    }
    ASSERT_TRUE(
        NS_SUCCEEDED(runTestSuite(testPol, 1, kFuzzyExpectedPolicyCount)));
  }
}
#endif
// ======================= TestFuzzyPoliciesIncDir ===================
// In a similar fashion as in TestFuzzyPolicies, we again (pseudo) randomly
// generate input for the parser, but this time also include a valid directive
// followed by the random input.
#if RUN_OFFLINE_TESTS
TEST(CSPParser, FuzzyPoliciesIncDir)
{
  // init srand with 0 so we get same results
  srand(0);
  PolicyTest testPol[1];
  memset(&testPol[0].policy, '\0', kMaxPolicyLength);
  char defaultSrc[] = "default-src ";
  int defaultSrcLen = sizeof(defaultSrc) - 1;
  // copy default-src into the policy array
  memcpy(&testPol[0].policy, &defaultSrc, (defaultSrcLen * sizeof(char)));
  for (uint32_t index = 0; index < kFuzzyRuns; index++) {
    // randomly select the length of the next policy
    uint32_t polLength = rand() % (kMaxPolicyLength - defaultSrcLen);
    // reset memory of the policy string, but leave default-src.
    memset((&(testPol[0].policy) + (defaultSrcLen * sizeof(char))), '\0',
           (kMaxPolicyLength - defaultSrcLen) * sizeof(char));
    // do not start at index 0 so we do not overwrite 'default-src'
    for (uint32_t i = defaultSrcLen; i < polLength; i++) {
      // fill the policy array with random ASCII chars
      testPol[0].policy[i] = static_cast<char>(rand() % 128);
    }
    ASSERT_TRUE(
        NS_SUCCEEDED(runTestSuite(testPol, 1, kFuzzyExpectedPolicyCount)));
  }
}
#endif
// ====================== TestFuzzyPoliciesIncDirLimASCII ============
// Same as TestFuzzyPoliciesIncDir() but using limited ASCII,
// which represents more likely input.
#if RUN_OFFLINE_TESTS
TEST(CSPParser, FuzzyPoliciesIncDirLimASCII)
{
  char input[] =
      "1234567890"
      "abcdefghijklmnopqrstuvwxyz"
      "ABCDEFGHIJKLMNOPQRSTUVWZYZ"
      "!@#^&*()-+_=";
  // init srand with 0 so we get same results
  srand(0);
  PolicyTest testPol[1];
  memset(&testPol[0].policy, '\0', kMaxPolicyLength);
  char defaultSrc[] = "default-src ";
  int defaultSrcLen = sizeof(defaultSrc) - 1;
  // copy default-src into the policy array
  memcpy(&testPol[0].policy, &defaultSrc, (defaultSrcLen * sizeof(char)));
  for (uint32_t index = 0; index < kFuzzyRuns; index++) {
    // randomly select the length of the next policy
    uint32_t polLength = rand() % (kMaxPolicyLength - defaultSrcLen);
    // reset memory of the policy string, but leave default-src.
    memset((&(testPol[0].policy) + (defaultSrcLen * sizeof(char))), '\0',
           (kMaxPolicyLength - defaultSrcLen) * sizeof(char));
    // do not start at index 0 so we do not overwrite 'default-src'
    for (uint32_t i = defaultSrcLen; i < polLength; i++) {
      // fill the policy array with chars from the pre-defined input
      uint32_t inputIndex = rand() % sizeof(input);
      testPol[0].policy[i] = input[inputIndex];
    }
    ASSERT_TRUE(
        NS_SUCCEEDED(runTestSuite(testPol, 1, kFuzzyExpectedPolicyCount)));
  }
}
#endif