GDPR-IAB-TCFv2

 view release on metacpan or  search on metacpan

t/14-cmp-validator.t  view on Meta::CPAN

      network_ok  => 1,
      http_client => $fake,
      verify_ssl  => 0,
    );
  }
  qr/http_client and verify_ssl\/timeout are mutually exclusive/, "http_client + verify_ssl croaks";

  throws_ok {
    GDPR::IAB::TCFv2::CMPValidator->new(
      url         => 'https://example.invalid/',
      network_ok  => 1,
      http_client => $fake,
      timeout     => 60,
    );
  }
  qr/http_client and verify_ssl\/timeout are mutually exclusive/, "http_client + timeout croaks";
};

subtest "CMPValidator: http_client injection drives load_from_url" => sub {

  # Stable raw JSON for two known CMPs; lastUpdated kept fresh so no
  # staleness warning leaks into the test output.
  my $json = '{"lastUpdated":"2026-04-01T00:00:00Z",' . '"cmps":{"7":{"id":7},"42":{"id":42}}}';

  my $fake = FakeHttp->new({success => 1, content => $json});

  my $v = GDPR::IAB::TCFv2::CMPValidator->new(
    url         => 'https://does-not-matter.example/cmp.json',
    network_ok  => 1,
    http_client => $fake,
    now         => $now_fresh,
  );

  is_deeply $fake->{calls}, ['https://does-not-matter.example/cmp.json'],
    "the URL passed to ->get was the URL given to the constructor";

  ok $v->is_valid(7),   "CMP 7 from injected response is valid";
  ok $v->is_valid(42),  "CMP 42 from injected response is valid";
  ok !$v->is_valid(99), "CMP 99 is unknown (proves the response was used)";
};

subtest "CMPValidator: failed http_client response croaks with the reason" => sub {
  my $fake = FakeHttp->new({success => 0, status => 599, reason => "Connection refused"});

  throws_ok {
    GDPR::IAB::TCFv2::CMPValidator->new(
      url         => 'https://example.invalid/cmp.json',
      network_ok  => 1,
      http_client => $fake,
    );
  }
  qr/Failed to fetch CMP list.*Connection refused/, "failed response surfaces the reason text";
};

subtest "CMPValidator: env_proxy is honored on the default client" => sub {

  # Proves the default HTTP::Tiny is constructed with env_proxy => 1
  # by setting an unreachable proxy and asserting the failure mentions
  # it. Skip if the surrounding environment already has a real proxy
  # configured -- we don't want to disturb the user's shell.
  plan skip_all => "http_proxy already set in env" if $ENV{http_proxy} || $ENV{HTTP_PROXY};
  plan skip_all => "HTTP::Tiny not installed" unless eval { require HTTP::Tiny; 1 };

  local $ENV{http_proxy} = 'http://127.0.0.1:1';

  throws_ok {
    GDPR::IAB::TCFv2::CMPValidator->new(url => 'http://example.invalid/cmp.json', network_ok => 1, timeout => 2,);
  }
  qr/Failed to fetch CMP list/, "fetch fails with the unreachable proxy in env (env_proxy was applied)";
};

subtest 'lifecycle state: active / deleted / unknown' => sub {
  my $now = 1776254400;                            # 2026-04-15
  my $v   = GDPR::IAB::TCFv2::CMPValidator->new(
    now  => $now,
    data => '{"lastUpdated":"2026-04-10T00:00:00Z","cmps":{'
      . '"21":{"id":21},'
      . '"22":{"id":22,"deletedDate":"2020-01-01T00:00:00Z"}' . '}}',
  );

  is($v->state(21, $now), 'active',  'present, no deletedDate => active');
  is($v->state(22, $now), 'deleted', 'present, past deletedDate => deleted');
  is($v->state(99, $now), 'unknown', 'absent => unknown');
};

done_testing;



( run in 0.954 second using v1.01-cache-2.11-cpan-483215c6ad5 )