// Copyright 2012 Google Inc.
//
// Licensed 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.
//
// Author: morlovich@google.com (Maksim Orlovich)

#include "pagespeed/kernel/base/inline_slist.h"

#include "pagespeed/kernel/base/basictypes.h"
#include "pagespeed/kernel/base/gtest.h"
#include "pagespeed/kernel/base/string.h"
#include "pagespeed/kernel/base/string_util.h"

namespace net_instaweb {

namespace {

class IntElement : public InlineSListElement<IntElement> {
 public:
  explicit IntElement(int n) : num_(n) { }

  const int num() const { return num_; }
  void set_num(int num) { num_ = num; }

 private:
  int num_;

  DISALLOW_COPY_AND_ASSIGN(IntElement);
};

typedef InlineSList<IntElement> IntList;

class InlineSListTest : public testing::Test {
 protected:
  // Dump the list value. Assumes the list only contains small numbers,
  // but is thorough in checking various iteration interfaces, as well
  // as ,->, Get() and *.
  GoogleString Dump() {
    GoogleString dump1, dump2, dump3, dump4, dump5, dump6;

    for (IntList::iterator i = ints_.begin(); i != ints_.end(); ++i) {
      dump1.push_back(i->num() + '0');
    }

    for (IntList::iterator i = ints_.begin(); i != ints_.end(); ++i) {
      dump2.push_back((*i).num() + '0');
    }

    for (IntList::iterator i = ints_.begin(); i != ints_.end(); ++i) {
      dump3.push_back(i.Get()->num() + '0');
    }

    const IntList& cints = const_cast<const IntList&>(ints_);
    for (IntList::const_iterator i = cints.begin(); i != cints.end(); ++i) {
      dump4.push_back(i->num() + '0');
    }

    for (IntList::const_iterator i = cints.begin(); i != cints.end(); ++i) {
      dump5.push_back((*i).num() + '0');
    }

    for (IntList::const_iterator i = cints.begin(); i != cints.end(); ++i) {
      dump6.push_back(i.Get()->num() + '0');
    }

    EXPECT_EQ(dump1, dump2);
    EXPECT_EQ(dump1, dump3);
    EXPECT_EQ(dump1, dump4);
    EXPECT_EQ(dump1, dump5);
    EXPECT_EQ(dump1, dump6);
    return dump1;
  }

  IntList ints_;
};

TEST_F(InlineSListTest, BasicOperation) {
  EXPECT_TRUE(ints_.IsEmpty());
  EXPECT_STREQ("", Dump());

  ints_.Append(new IntElement(0));
  EXPECT_FALSE(ints_.IsEmpty());
  EXPECT_STREQ("0", Dump());

  ints_.Append(new IntElement(1));
  EXPECT_FALSE(ints_.IsEmpty());
  EXPECT_STREQ("01", Dump());

  ints_.Append(new IntElement(2));
  EXPECT_FALSE(ints_.IsEmpty());
  EXPECT_STREQ("012", Dump());
}

TEST_F(InlineSListTest, DestructEmpty) {
  // Make sure ~IntList works with no elements element.
}

TEST_F(InlineSListTest, Destruct1) {
  // Make sure ~IntList works with 1 element.
  ints_.Append(new IntElement(0));
}

TEST_F(InlineSListTest, Remove1) {
  // Remove the sole item in 1-entry list.
  ints_.Append(new IntElement(0));
  EXPECT_EQ(0, ints_.Last()->num());
  IntList::iterator iter(ints_.begin());
  EXPECT_NE(ints_.end(), iter);
  ints_.Erase(&iter);
  EXPECT_EQ(ints_.end(), iter);
  EXPECT_TRUE(ints_.IsEmpty());
  EXPECT_STREQ("", Dump());
}

TEST_F(InlineSListTest, RemoveLast) {
  // Remove last item of 0,1 list.
  ints_.Append(new IntElement(0));
  ints_.Append(new IntElement(1));
  EXPECT_EQ(1, ints_.Last()->num());

  IntList::iterator iter(ints_.begin());
  EXPECT_NE(ints_.end(), iter);
  EXPECT_EQ(0, iter->num());

  ++iter;
  EXPECT_NE(ints_.end(), iter);
  EXPECT_EQ(1, iter->num());

  ints_.Erase(&iter);
  EXPECT_EQ(ints_.end(), iter);
  EXPECT_STREQ("0", Dump());
  EXPECT_EQ(0, ints_.Last()->num());
}

TEST_F(InlineSListTest, RemoveFirst) {
  // Remove first item of 0,1 list.
  ints_.Append(new IntElement(0));
  ints_.Append(new IntElement(1));

  IntList::iterator iter(ints_.begin());
  EXPECT_NE(ints_.end(), iter);
  EXPECT_EQ(0, iter->num());

  ints_.Erase(&iter);
  EXPECT_NE(ints_.end(), iter);
  EXPECT_EQ(1, iter->num());

  ++iter;
  EXPECT_EQ(ints_.end(), iter);
  EXPECT_STREQ("1", Dump());
}

TEST_F(InlineSListTest, RemoveOdd) {
  for (int i = 0; i < 10; ++i) {
    ints_.Append(new IntElement(i));
  }
  EXPECT_STREQ("0123456789", Dump());

  IntList::iterator iter(ints_.begin());
  while (iter != ints_.end()) {
    if ((iter->num() % 2) == 1) {
      ints_.Erase(&iter);
    } else {
      ++iter;
    }
  }
  EXPECT_STREQ("02468", Dump());
}

}  // namespace

}  // namespace net_instaweb
