root/sync/internal_api/public/util/immutable_unittest.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. copy_count_
  2. GetToken
  3. RecordCopy
  4. GetCopyCount
  5. GetToken
  6. GetCopyCount
  7. swap
  8. Swap
  9. swap
  10. swap
  11. TEST_F
  12. TEST_F
  13. TEST_F
  14. TEST_F
  15. RunTokenTest
  16. TEST_F
  17. TEST_F
  18. TEST_F
  19. TEST_F
  20. TEST_F
  21. RunTokenContainerTest
  22. TEST_F
  23. TEST_F
  24. TEST_F
  25. TEST_F
  26. TEST_F

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "sync/internal_api/public/util/immutable.h"

#include <algorithm>
#include <cstddef>
#include <deque>
#include <list>
#include <set>
#include <string>
#include <vector>

#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace syncer {

// Helper class that keeps track of the token passed in at
// construction and how many times that token is copied.
class TokenCore : public base::RefCounted<TokenCore> {
 public:
  explicit TokenCore(const char* token) : token_(token), copy_count_(0) {}

  const char* GetToken() const { return token_; }

  void RecordCopy() { ++copy_count_; }

  int GetCopyCount() const { return copy_count_; }

 private:
  friend class base::RefCounted<TokenCore>;

  ~TokenCore() {}

  const char* const token_;
  int copy_count_;
};

enum SwapBehavior {
  USE_DEFAULT_SWAP,
  USE_FAST_SWAP_VIA_ADL,
  USE_FAST_SWAP_VIA_SPECIALIZATION
};

const char kEmptyToken[] = "<empty token>";

// Base class for various token classes, differing in swap behavior.
template <SwapBehavior>
class TokenBase {
 public:
  TokenBase() : core_(new TokenCore(kEmptyToken)) {}

  explicit TokenBase(const char* token) : core_(new TokenCore(token)) {}

  TokenBase(const TokenBase& other) : core_(other.core_) {
    core_->RecordCopy();
  }

  TokenBase& operator=(const TokenBase& other) {
    core_ = other.core_;
    core_->RecordCopy();
    return *this;
  }

  const char* GetToken() const {
    return core_->GetToken();
  }

  int GetCopyCount() const {
    return core_->GetCopyCount();
  }

  // For associative containers.
  bool operator<(const TokenBase& other) const {
    return std::string(GetToken()) < std::string(other.GetToken());
  }

  // STL-style swap.
  void swap(TokenBase& other) {
    using std::swap;
    swap(other.core_, core_);
  }

  // Google-style swap.
  void Swap(TokenBase* other) {
    using std::swap;
    swap(other->core_, core_);
  }

 private:
  scoped_refptr<TokenCore> core_;
};

typedef TokenBase<USE_DEFAULT_SWAP> Token;
typedef TokenBase<USE_FAST_SWAP_VIA_ADL> ADLToken;
typedef TokenBase<USE_FAST_SWAP_VIA_SPECIALIZATION> SpecializationToken;

void swap(ADLToken& t1, ADLToken& t2) {
  t1.Swap(&t2);
}

}  // namespace syncer

// Allowed by the standard (17.4.3.1/1).
namespace std {

template <>
void swap(syncer::SpecializationToken& t1,
          syncer::SpecializationToken& t2) {
  t1.Swap(&t2);
}

}  // namespace

namespace syncer {
namespace {

class ImmutableTest : public ::testing::Test {};

TEST_F(ImmutableTest, Int) {
  int x = 5;
  Immutable<int> ix(&x);
  EXPECT_EQ(5, ix.Get());
  EXPECT_EQ(0, x);
}

TEST_F(ImmutableTest, IntCopy) {
  int x = 5;
  Immutable<int> ix = Immutable<int>(&x);
  EXPECT_EQ(5, ix.Get());
  EXPECT_EQ(0, x);
}

TEST_F(ImmutableTest, IntAssign) {
  int x = 5;
  Immutable<int> ix;
  EXPECT_EQ(0, ix.Get());
  ix = Immutable<int>(&x);
  EXPECT_EQ(5, ix.Get());
  EXPECT_EQ(0, x);
}

TEST_F(ImmutableTest, IntMakeImmutable) {
  int x = 5;
  Immutable<int> ix = MakeImmutable(&x);
  EXPECT_EQ(5, ix.Get());
  EXPECT_EQ(0, x);
}

template <typename T, typename ImmutableT>
void RunTokenTest(const char* token, bool expect_copies) {
  SCOPED_TRACE(token);
  T t(token);
  EXPECT_EQ(token, t.GetToken());
  EXPECT_EQ(0, t.GetCopyCount());

  ImmutableT immutable_t(&t);
  EXPECT_EQ(token, immutable_t.Get().GetToken());
  EXPECT_EQ(kEmptyToken, t.GetToken());
  EXPECT_EQ(expect_copies, immutable_t.Get().GetCopyCount() > 0);
  EXPECT_EQ(expect_copies, t.GetCopyCount() > 0);
}

TEST_F(ImmutableTest, Token) {
  RunTokenTest<Token, Immutable<Token> >("Token", true /* expect_copies */);
}

TEST_F(ImmutableTest, TokenSwapMemFnByRef) {
  RunTokenTest<Token, Immutable<Token, HasSwapMemFnByRef<Token> > >(
      "TokenSwapMemFnByRef", false /* expect_copies */);
}

TEST_F(ImmutableTest, TokenSwapMemFnByPtr) {
  RunTokenTest<Token, Immutable<Token, HasSwapMemFnByPtr<Token> > >(
      "TokenSwapMemFnByPtr", false /* expect_copies */);
}

TEST_F(ImmutableTest, ADLToken) {
  RunTokenTest<ADLToken, Immutable<ADLToken> >(
      "ADLToken", false /* expect_copies */);
}

TEST_F(ImmutableTest, SpecializationToken) {
  RunTokenTest<SpecializationToken, Immutable<SpecializationToken> >(
      "SpecializationToken", false /* expect_copies */);
}

template <typename C, typename ImmutableC>
void RunTokenContainerTest(const char* token) {
  SCOPED_TRACE(token);
  const Token tokens[] = { Token(), Token(token) };
  const size_t token_count = arraysize(tokens);
  C c(tokens, tokens + token_count);
  const int copy_count = c.begin()->GetCopyCount();
  EXPECT_GT(copy_count, 0);
  for (typename C::const_iterator it = c.begin(); it != c.end(); ++it) {
    EXPECT_EQ(copy_count, it->GetCopyCount());
  }

  // Make sure that making the container immutable doesn't incur any
  // copies of the tokens.
  ImmutableC immutable_c(&c);
  EXPECT_TRUE(c.empty());
  ASSERT_EQ(token_count, immutable_c.Get().size());
  int i = 0;
  for (typename C::const_iterator it = c.begin(); it != c.end(); ++it) {
    EXPECT_EQ(tokens[i].GetToken(), it->GetToken());
    EXPECT_EQ(copy_count, it->GetCopyCount());
    ++i;
  }
}

TEST_F(ImmutableTest, Vector) {
  RunTokenContainerTest<std::vector<Token>, Immutable<std::vector<Token> > >(
      "Vector");
}

TEST_F(ImmutableTest, VectorSwapMemFnByRef) {
  RunTokenContainerTest<
    std::vector<Token>,
    Immutable<std::vector<Token>, HasSwapMemFnByRef<std::vector<Token> > > >(
        "VectorSwapMemFnByRef");
}

// http://crbug.com/129128
#if defined(OS_WIN)
#define MAYBE_Deque DISABLED_Deque
#else
#define MAYBE_Deque Deque
#endif
TEST_F(ImmutableTest, MAYBE_Deque) {
  RunTokenContainerTest<std::deque<Token>, Immutable<std::deque<Token> > >(
      "Deque");
}

TEST_F(ImmutableTest, List) {
  RunTokenContainerTest<std::list<Token>, Immutable<std::list<Token> > >(
      "List");
}

TEST_F(ImmutableTest, Set) {
  RunTokenContainerTest<std::set<Token>, Immutable<std::set<Token> > >(
      "Set");
}

}  // namespace
}  // namespace syncer

/* [<][>][^][v][top][bottom][index][help] */