/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */


// Unit-test the srcset slot.

#include "net/instaweb/rewriter/public/srcset_slot.h"

#include "net/instaweb/rewriter/public/resource.h"
#include "net/instaweb/rewriter/public/rewrite_driver.h"
#include "net/instaweb/rewriter/public/rewrite_filter.h"
#include "net/instaweb/rewriter/public/rewrite_test_base.h"
#include "pagespeed/kernel/base/gtest.h"
#include "pagespeed/kernel/base/scoped_ptr.h"
#include "pagespeed/kernel/base/string.h"
#include "pagespeed/kernel/html/html_element.h"
#include "pagespeed/kernel/html/html_name.h"
#include "pagespeed/kernel/html/html_writer_filter.h"
#include "pagespeed/kernel/http/content_type.h"

namespace {

static const char kHtmlUrl[] = "http://www.example.com/dir/a.html";

}  // namespace

namespace net_instaweb {

TEST(SrcSetSlotParseTest, ParseAndSerialize) {
  std::vector<SrcSetSlotCollection::ImageCandidate> out;
  SrcSetSlotCollection::ParseSrcSet(
      "    ,a.jpg, b.jpg 100w,, c.jpg 10h, d.jpg (very, fancy) , e,f.jpg 10w",
      &out);
  ASSERT_EQ(5, out.size());
  EXPECT_EQ("a.jpg", out[0].url);
  EXPECT_EQ("", out[0].descriptor);

  EXPECT_EQ("b.jpg", out[1].url);
  EXPECT_EQ("100w", out[1].descriptor);

  EXPECT_EQ("c.jpg", out[2].url);
  EXPECT_EQ("10h", out[2].descriptor);

  EXPECT_EQ("d.jpg", out[3].url);
  EXPECT_EQ("(very, fancy)", out[3].descriptor);

  EXPECT_EQ("e,f.jpg", out[4].url);
  EXPECT_EQ("10w", out[4].descriptor);

  EXPECT_EQ("a.jpg, b.jpg 100w, c.jpg 10h, d.jpg (very, fancy), e,f.jpg 10w",
            SrcSetSlotCollection::Serialize(out));

  std::vector<SrcSetSlotCollection::ImageCandidate> out2;
  SrcSetSlotCollection::ParseSrcSet(
      "a.jpg ,b.jpg 100w , c.jpg 200w, d.jpg",
      &out2);
  ASSERT_EQ(4, out2.size());
  EXPECT_EQ("a.jpg", out2[0].url);
  EXPECT_EQ("", out2[0].descriptor);

  EXPECT_EQ("b.jpg", out2[1].url);
  EXPECT_EQ("100w", out2[1].descriptor);

  EXPECT_EQ("c.jpg", out2[2].url);
  EXPECT_EQ("200w", out2[2].descriptor);

  EXPECT_EQ("d.jpg", out2[3].url);
  EXPECT_EQ("", out2[3].descriptor);

  EXPECT_EQ("a.jpg, b.jpg 100w, c.jpg 200w, d.jpg",
            SrcSetSlotCollection::Serialize(out2));
}

class SrcSetSlotTest : public RewriteTestBase {
 protected:
  bool AddBody() const override { return false; }

  void SetUp() override {
    RewriteTestBase::SetUp();

    RewriteDriver* driver = rewrite_driver();
    driver->AddFilters();
    ASSERT_TRUE(driver->StartParseId(kHtmlUrl, "srcset_slot_test",
                                     kContentTypeHtml));
    element_ = driver->NewElement(nullptr, HtmlName::kImg);
    driver->AddAttribute(element_, HtmlName::kSrcset,
                         "a.jpg, b.jpg 100w, c.png 1000w");
    attribute_ = element_->FindAttribute(HtmlName::kSrcset);
    driver->AddElement(element_, 42 /* line number */);
    driver->CloseElement(element_, HtmlElement::BRIEF_CLOSE, 43 /* line # */);
  }

  void TearDown() override {
    rewrite_driver()->FinishParse();
    RewriteTestBase::TearDown();
  }

  GoogleString GetHtmlDomAsString() {
    output_buffer_.clear();
    html_parse()->ApplyFilter(html_writer_filter_.get());
    return output_buffer_;
  }

  HtmlElement* element_;
  HtmlElement::Attribute* attribute_;
};

TEST_F(SrcSetSlotTest, BasicOperation) {
  SetupWriter();
  RefCountedPtr<SrcSetSlotCollection> collection(new SrcSetSlotCollection(
      rewrite_driver(),
      element_,
      attribute_));
  collection->Initialize(rewrite_driver()->FindFilter("ic"));
  ASSERT_EQ(3, collection->num_image_candidates());
  EXPECT_EQ("a.jpg", collection->url(0));
  EXPECT_EQ("", collection->descriptor(0));
  EXPECT_EQ("b.jpg", collection->url(1));
  EXPECT_EQ("100w", collection->descriptor(1));
  EXPECT_EQ("c.png", collection->url(2));
  EXPECT_EQ("1000w", collection->descriptor(2));
  ResourceSlotPtr slot0(collection->slot(0));
  EXPECT_EQ("http://www.example.com/dir/a.jpg", slot0->resource()->url());
  ResourceSlotPtr slot1(collection->slot(1));
  EXPECT_EQ("http://www.example.com/dir/b.jpg", slot1->resource()->url());
  ResourceSlotPtr slot2(collection->slot(2));
  EXPECT_EQ("http://www.example.com/dir/c.png", slot2->resource()->url());

  // Now rewrite the 3 slots, but only render 2, with 1 prevented
  // from rendering.
  bool unused;
  GoogleUrl optimized_a("http://www.example.com/dir/a.pagespeed.webp");
  slot0->SetResource(
    rewrite_driver()->CreateInputResource(
        optimized_a, RewriteDriver::InputRole::kImg, &unused));

  GoogleUrl optimized_b("http://www.example.com/dir/b.pagespeed.webp");
  slot1->SetResource(
    rewrite_driver()->CreateInputResource(
        optimized_b, RewriteDriver::InputRole::kImg, &unused));

  GoogleUrl optimized_c("http://www.example.com/dir/c.pagespeed.png");
  slot2->SetResource(
    rewrite_driver()->CreateInputResource(
        optimized_c, RewriteDriver::InputRole::kImg, &unused));

  slot0->set_disable_rendering(true);
  slot0->Render();
  slot1->Render();

  // Empty descriptor output a bit silly... not expected in real life, though.
  EXPECT_EQ("srcset_slot_test:42-43 srcset entry for ",
            slot0->LocationString());
  EXPECT_EQ("srcset_slot_test:42-43 srcset entry for 100w",
            slot1->LocationString());
  EXPECT_EQ("srcset_slot_test:42-43 srcset entry for 1000w",
            slot2->LocationString());

  EXPECT_EQ("<img srcset=\"a.jpg, b.pagespeed.webp 100w, c.png 1000w\"/>",
            GetHtmlDomAsString());
  collection->Detach();
}

}  // namespace net_instaweb
