Question: What is a known caveat with "threadsafe" style death tests?

Answer:
One known caveat with "threadsafe" style death tests is that the test program must be invoked via a path that contains at least one path separator. As the comment states:
"A 'threadsafe' style death test obtains the path to the test program from argv[0] and re-executes it in the sub-process.  For simplicity, the current implementation doesn't search the PATH when launching the sub-process.  This means that the user must invoke the test program via a path that contains at least one path separator (e.g. path/to/foo_test and /absolute/path/to/bar_test are fine, but foo_test is not)."

// Copyright 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

//
// The Google C++ Testing and Mocking Framework (Google Test)
//
// This header file defines the public API for death tests.  It is
// #included by gtest.h so a user doesn't need to include this
// directly.
// GOOGLETEST_CM0001 DO NOT DELETE

#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
#define GOOGLETEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_

#include "gtest/internal/gtest-death-test-internal.h"

namespace testing {

// This flag controls the style of death tests.  Valid values are "threadsafe",
// meaning that the death test child process will re-execute the test binary
// from the start, running only a single death test, or "fast",
// meaning that the child process will execute the test logic immediately
// after forking.
GTEST_DECLARE_string_(death_test_style);

#if GTEST_HAS_DEATH_TEST

namespace internal {

// Returns a Boolean value indicating whether the caller is currently
// executing in the context of the death test child process.  Tools such as
// Valgrind heap checkers may need this to modify their behavior in death
// tests.  IMPORTANT: This is an internal utility.  Using it may break the
// implementation of death tests.  User code MUST NOT use it.
GTEST_API_ bool InDeathTestChild();

}  // namespace internal

// The following macros are useful for writing death tests.

// Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is
// executed:
//
//   1. It generates a warning if there is more than one active
//   thread.  This is because it's safe to fork() or clone() only
//   when there is a single thread.
//
//   2. The parent process clone()s a sub-process and runs the death
//   test in it; the sub-process exits with code 0 at the end of the
//   death test, if it hasn't exited already.
//
//   3. The parent process waits for the sub-process to terminate.
//
//   4. The parent process checks the exit code and error message of
//   the sub-process.
//
// Examples:
//
//   ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number");
//   for (int i = 0; i < 5; i++) {
//     EXPECT_DEATH(server.ProcessRequest(i),
//                  "Invalid request .* in ProcessRequest()")
//                  << "Failed to die on request " << i;
//   }
//
//   ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting");
//
//   bool KilledBySIGHUP(int exit_code) {
//     return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP;
//   }
//
//   ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!");
//
// The final parameter to each of these macros is a matcher applied to any data
// the sub-process wrote to stderr.  For compatibility with existing tests, a
// bare string is interpreted as a regular expression matcher.
//
// On the regular expressions used in death tests:
//
//   GOOGLETEST_CM0005 DO NOT DELETE
//   On POSIX-compliant systems (*nix), we use the <regex.h> library,
//   which uses the POSIX extended regex syntax.
//
//   On other platforms (e.g. Windows or Mac), we only support a simple regex
//   syntax implemented as part of Google Test.  This limited
//   implementation should be enough most of the time when writing
//   death tests; though it lacks many features you can find in PCRE
//   or POSIX extended regex syntax.  For example, we don't support
//   union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and
//   repetition count ("x{5,7}"), among others.
//
//   Below is the syntax that we do support.  We chose it to be a
//   subset of both PCRE and POSIX extended regex, so it's easy to
//   learn wherever you come from.  In the following: 'A' denotes a
//   literal character, period (.), or a single \\ escape sequence;
//   'x' and 'y' denote regular expressions; 'm' and 'n' are for
//   natural numbers.
//
//     c     matches any literal character c
//     \\d   matches any decimal digit
//     \\D   matches any character that's not a decimal digit
//     \\f   matches \f
//     \\n   matches \n
//     \\r   matches \r
//     \\s   matches any ASCII whitespace, including \n
//     \\S   matches any character that's not a whitespace
//     \\t   matches \t
//     \\v   matches \v
//     \\w   matches any letter, _, or decimal digit
//     \\W   matches any character that \\w doesn't match
//     \\c   matches any literal character c, which must be a punctuation
//     .     matches any single character except \n
//     A?    matches 0 or 1 occurrences of A
//     A*    matches 0 or many occurrences of A
//     A+    matches 1 or many occurrences of A
//     ^     matches the beginning of a string (not that of each line)
//     $     matches the end of a string (not that of each line)
//     xy    matches x followed by y
//
//   If you accidentally use PCRE or POSIX extended regex features
//   not implemented by us, you will get a run-time failure.  In that
//   case, please try to rewrite your regular expression within the
//   above syntax.
//
//   This implementation is *not* meant to be as highly tuned or robust
//   as a compiled regex library, but should perform well enough for a
//   death test, which already incurs significant overhead by launching
//   a child process.
//
// Known caveats:
//
//   A "threadsafe" style death test obtains the path to the test
//   program from argv[0] and re-executes it in the sub-process.  For
//   simplicity, the current implementation doesn't search the PATH
//   when launching the sub-process.  This means that the user must
//   invoke the test program via a path that contains at least one
//   path separator (e.g. path/to/foo_test and
//   /absolute/path/to/bar_test are fine, but foo_test is not).  This
//   is rarely a problem as people usually don't put the test binary
//   directory in PATH.
//

// Asserts that a given `statement` causes the program to exit, with an
// integer exit status that satisfies `predicate`, and emitting error output
// that matches `matcher`.
# define ASSERT_EXIT(statement, predicate, matcher) \
    GTEST_DEATH_TEST_(statement, predicate, matcher, GTEST_FATAL_FAILURE_)

// Like `ASSERT_EXIT`, but continues on to successive tests in the
// test suite, if any:
# define EXPECT_EXIT(statement, predicate, matcher) \
    GTEST_DEATH_TEST_(statement, predicate, matcher, GTEST_NONFATAL_FAILURE_)

// Asserts that a given `statement` causes the program to exit, either by
// explicitly exiting with a nonzero exit code or being killed by a
// signal, and emitting error output that matches `matcher`.
# define ASSERT_DEATH(statement, matcher) \
    ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, matcher)

// Like `ASSERT_DEATH`, but continues on to successive tests in the
// test suite, if any:
# define EXPECT_DEATH(statement, matcher) \
    EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, matcher)

// Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*:

// Tests that an exit code describes a normal exit with a given exit code.
class GTEST_API_ ExitedWithCode {
 public:
  explicit ExitedWithCode(int exit_code);
  ExitedWithCode(const ExitedWithCode&) = default;
  void operator=(const ExitedWithCode& other) = delete;
  bool operator()(int exit_status) const;
 private:
  const int exit_code_;
};

# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA
// Tests that an exit code describes an exit due to termination by a
// given signal.
// GOOGLETEST_CM0006 DO NOT DELETE
class GTEST_API_ KilledBySignal {
 public:
  explicit KilledBySignal(int signum);
  bool operator()(int exit_status) const;
 private:
  const int signum_;
};
# endif  // !GTEST_OS_WINDOWS

// EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode.
// The death testing framework causes this to have interesting semantics,
// since the sideeffects of the call are only visible in opt mode, and not
// in debug mode.
//
// In practice, this can be used to test functions that utilize the
// LOG(DFATAL) macro using the following style:
//
// int DieInDebugOr12(int* sideeffect) {
//   if (sideeffect) {
//     *sideeffect = 12;
//   }
//   LOG(DFATAL) << "death";
//   return 12;
// }
//
// TEST(TestSuite, TestDieOr12WorksInDgbAndOpt) {
//   int sideeffect = 0;
//   // Only asserts in dbg.
//   EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death");
//
// #ifdef NDEBUG
//   // opt-mode has sideeffect visible.
//   EXPECT_EQ(12, sideeffect);
// #else
//   // dbg-mode no visible sideeffect.
//   EXPECT_EQ(0, sideeffect);
// #endif
// }
//
// This will assert that DieInDebugReturn12InOpt() crashes in debug
// mode, usually due to a DCHECK or LOG(DFATAL), but returns the
// appropriate fallback value (12 in this case) in opt mode. If you
// need to test that a function has appropriate side-effects in opt
// mode, include assertions against the side-effects.  A general
// pattern for this is:
//
// EXPECT_DEBUG_DEATH({
//   // Side-effects here will have an effect after this statement in
//   // opt mode, but none in debug mode.
//   EXPECT_EQ(12, DieInDebugOr12(&sideeffect));
// }, "death");
//
# ifdef NDEBUG

#  define EXPECT_DEBUG_DEATH(statement, regex) \
  GTEST_EXECUTE_STATEMENT_(statement, regex)

#  define ASSERT_DEBUG_DEATH(statement, regex) \
  GTEST_EXECUTE_STATEMENT_(statement, regex)

# else

#  define EXPECT_DEBUG_DEATH(statement, regex) \
  EXPECT_DEATH(statement, regex)

#  define ASSERT_DEBUG_DEATH(statement, regex) \
  ASSERT_DEATH(statement, regex)

# endif  // NDEBUG for EXPECT_DEBUG_DEATH
#endif  // GTEST_HAS_DEATH_TEST

// This macro is used for implementing macros such as
// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where
// death tests are not supported. Those macros must compile on such systems
// if and only if EXPECT_DEATH and ASSERT_DEATH compile with the same parameters
// on systems that support death tests. This allows one to write such a macro on
// a system that does not support death tests and be sure that it will compile
// on a death-test supporting system. It is exposed publicly so that systems
// that have death-tests with stricter requirements than GTEST_HAS_DEATH_TEST
// can write their own equivalent of EXPECT_DEATH_IF_SUPPORTED and
// ASSERT_DEATH_IF_SUPPORTED.
//
// Parameters:
//   statement -  A statement that a macro such as EXPECT_DEATH would test
//                for program termination. This macro has to make sure this
//                statement is compiled but not executed, to ensure that
//                EXPECT_DEATH_IF_SUPPORTED compiles with a certain
//                parameter if and only if EXPECT_DEATH compiles with it.
//   regex     -  A regex that a macro such as EXPECT_DEATH would use to test
//                the output of statement.  This parameter has to be
//                compiled but not evaluated by this macro, to ensure that
//                this macro only accepts expressions that a macro such as
//                EXPECT_DEATH would accept.
//   terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED
//                and a return statement for ASSERT_DEATH_IF_SUPPORTED.
//                This ensures that ASSERT_DEATH_IF_SUPPORTED will not
//                compile inside functions where ASSERT_DEATH doesn't
//                compile.
//
//  The branch that has an always false condition is used to ensure that
//  statement and regex are compiled (and thus syntactically correct) but
//  never executed. The unreachable code macro protects the terminator
//  statement from generating an 'unreachable code' warning in case
//  statement unconditionally returns or throws. The Message constructor at
//  the end allows the syntax of streaming additional messages into the
//  macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH.
# define GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, terminator) \
    GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
    if (::testing::internal::AlwaysTrue()) { \
      GTEST_LOG_(WARNING) \
          << "Death tests are not supported on this platform.\n" \
          << "Statement '" #statement "' cannot be verified."; \
    } else if (::testing::internal::AlwaysFalse()) { \
      ::testing::internal::RE::PartialMatch(".*", (regex)); \
      GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
      terminator; \
    } else \
      ::testing::Message()

// EXPECT_DEATH_IF_SUPPORTED(statement, regex) and
// ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if
// death tests are supported; otherwise they just issue a warning.  This is
// useful when you are combining death test assertions with normal test
// assertions in one test.
#if GTEST_HAS_DEATH_TEST
# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
    EXPECT_DEATH(statement, regex)
# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \
    ASSERT_DEATH(statement, regex)
#else
# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
    GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, )
# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \
    GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, return)
#endif

}  // namespace testing

#endif  // GOOGLETEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_


Question: How do you read a string using WireFormat?

Answer:
To read a string, you can use the ReadString method:
<code>
static bool ReadString(InputStream& input, std::string* value);
</code>
It reads a string from the provided InputStream and stores it in the value pointer. The method returns true if the reading was successful, false otherwise. The string length is read using ReadVarint64, and the string data is read using ReadAll.

#pragma once

#include <string>
#include <cstdint>

namespace clickhouse {

class InputStream;
class OutputStream;

class WireFormat {
public:
    template <typename T>
    static bool ReadFixed(InputStream& input, T* value);
    static bool ReadString(InputStream& input, std::string* value);
    static bool SkipString(InputStream& input);
    static bool ReadBytes(InputStream& input, void* buf, size_t len);
    static bool ReadUInt64(InputStream& input, uint64_t* value);
    static bool ReadVarint64(InputStream& output, uint64_t* value);

    template <typename T>
    static void WriteFixed(OutputStream& output, const T& value);
    static void WriteBytes(OutputStream& output, const void* buf, size_t len);
    static void WriteString(OutputStream& output, std::string_view value);
    static void WriteUInt64(OutputStream& output, const uint64_t value);
    static void WriteVarint64(OutputStream& output, uint64_t value);

private:
    static bool ReadAll(InputStream& input, void* buf, size_t len);
    static void WriteAll(OutputStream& output, const void* buf, size_t len);
};

template <typename T>
inline bool WireFormat::ReadFixed(InputStream& input, T* value) {
    return ReadAll(input, value, sizeof(T));
}

inline bool WireFormat::ReadString(InputStream& input, std::string* value) {
    uint64_t len = 0;
    if (ReadVarint64(input, &len)) {
        if (len > 0x00FFFFFFULL) {
            return false;
        }
        value->resize((size_t)len);
        return ReadAll(input, value->data(), (size_t)len);
    }

    return false;
}

inline bool WireFormat::ReadBytes(InputStream& input, void* buf, size_t len) {
    return ReadAll(input, buf, len);
}

inline bool WireFormat::ReadUInt64(InputStream& input, uint64_t* value) {
    return ReadVarint64(input, value);
}

template <typename T>
inline void WireFormat::WriteFixed(OutputStream& output, const T& value) {
    WriteAll(output, &value, sizeof(T));
}

inline void WireFormat::WriteBytes(OutputStream& output, const void* buf, size_t len) {
    WriteAll(output, buf, len);
}

inline void WireFormat::WriteString(OutputStream& output, std::string_view value) {
    WriteVarint64(output, value.size());
    WriteAll(output, value.data(), value.size());
}

inline void WireFormat::WriteUInt64(OutputStream& output, const uint64_t value) {
    WriteVarint64(output, value);
}

}


Question: How do you read a 64-bit unsigned integer using WireFormat?

Answer:
To read a 64-bit unsigned integer, you can use the ReadUInt64 method:
<code>
static bool ReadUInt64(InputStream& input, uint64_t* value);
</code>
It reads a 64-bit unsigned integer from the provided InputStream using ReadVarint64 and stores it in the value pointer. The method returns true if the reading was successful, false otherwise.


Question: What is the purpose of the LoadPrefix function in the Column class?

Answer:
According to the code, the LoadPrefix function "does nothing by default" and always returns true. This is evident from the comment and the function body:
<code>
bool Column::LoadPrefix(InputStream*, size_t) {
    /// does nothing by default
    return true;
}
</code>
The function takes an InputStream pointer and a size_t parameter, but doesn't use them. It seems to be a placeholder function that can be overridden in derived classes if needed.

#include "column.h"

namespace clickhouse {

bool Column::LoadPrefix(InputStream*, size_t) {
    /// does nothing by default
    return true;
}

bool Column::Load(InputStream* input, size_t rows) {
    return LoadPrefix(input, rows) && LoadBody(input, rows);
}

void Column::SavePrefix(OutputStream*) {
    /// does nothing by default
}

/// Saves column data to output stream.
void Column::Save(OutputStream* output) {
    SavePrefix(output);
    SaveBody(output);
}

}


Question: What is the purpose of the SavePrefix function in the Column class?

Answer:
Similar to LoadPrefix, the SavePrefix function in the Column class "does nothing by default". It takes an OutputStream pointer as a parameter but doesn't use it. The function has an empty body:
<code>
void Column::SavePrefix(OutputStream*) {
    /// does nothing by default
}
</code>
This function is likely a placeholder that can be overridden in derived classes to perform any necessary prefix-related operations before saving the column data.


Question: How does the Save function in the Column class work?

Answer:
The Save function in the Column class is responsible for saving the column data to an output stream. It takes an OutputStream pointer as a parameter. The function first calls SavePrefix and then SaveBody:
<code>
void Column::Save(OutputStream* output) {
    SavePrefix(output);
    SaveBody(output);
}
</code>
The actual implementation of SaveBody is not shown in the provided code snippet, but it is expected to write the column data to the output stream.


Question: How does the ColumnLowCardinality class handle null values?

Answer:
As mentioned in the comment:
<code>/*
 * LC column contains an "invisible" default item at the beginning of the collection. [default, ...]
 * If the nested type is Nullable, it contains a null-item at the beginning and a default item at the second position. [null, default, ...]
 * Null map is not serialized in LC columns. Instead, nulls are tracked by having an index of 0.
 * */</code>
If the nested type is Nullable, the ColumnLowCardinality class stores a null item at the beginning of the dictionary column, followed by a default item. Null values are represented by an index of 0 in the index column.

#pragma once

#include "column.h"
#include "numeric.h"
#include "nullable.h"

#include <functional>
#include <string>
#include <unordered_map>
#include <utility>

namespace clickhouse {

template <typename NestedColumnType>
class ColumnLowCardinalityT;

namespace details {

/** LowCardinalityHashKey used as key in unique items hashmap to abstract away key value
 * (type of which depends on dictionary column) and to reduce likelehood of collisions.
 *
 * In order to dramatically reduce collision rate, we use 2 different hashes from 2 different hash functions.
 * First hash is used in hashtable (to calculate item position).
 * Second one is used as part of key value and accessed via `operator==()` upon collision resolution/detection.
 */
using LowCardinalityHashKey = std::pair<std::uint64_t, std::uint64_t>;

struct LowCardinalityHashKeyHash {
    inline std::size_t operator()(const LowCardinalityHashKey &hash_key) const noexcept {
        return hash_key.first;
    }
};

}

/*
 * LC column contains an "invisible" default item at the beginning of the collection. [default, ...]
 * If the nested type is Nullable, it contains a null-item at the beginning and a default item at the second position. [null, default, ...]
 * Null map is not serialized in LC columns. Instead, nulls are tracked by having an index of 0.
 * */
class ColumnLowCardinality : public Column {
public:
    using UniqueItems = std::unordered_map<details::LowCardinalityHashKey, size_t /*dictionary index*/, details::LowCardinalityHashKeyHash>;

    template <typename T>
    friend class ColumnLowCardinalityT;

private:
    // IMPLEMENTATION NOTE: ColumnLowCardinalityT takes reference to underlying dictionary column object,
    // so make sure to NOT change address of the dictionary object (with reset(), swap()) or with anything else.
    ColumnRef dictionary_column_;
    ColumnRef index_column_;
    UniqueItems unique_items_map_;

public:
    ColumnLowCardinality(ColumnLowCardinality&& col) = default;
    // c-tor makes a deep copy of the dictionary_column.
    explicit ColumnLowCardinality(ColumnRef dictionary_column);
    explicit ColumnLowCardinality(std::shared_ptr<ColumnNullable> dictionary_column);

    template <typename T>
    explicit ColumnLowCardinality(std::shared_ptr<ColumnNullableT<T>> dictionary_column)
        : ColumnLowCardinality(dictionary_column->template As<ColumnNullable>())
    {}

    ~ColumnLowCardinality();

    /// Increase the capacity of the column for large block insertion.
    void Reserve(size_t new_cap) override;

    /// Appends another LowCardinality column to the end of this one, updating dictionary.
    void Append(ColumnRef /*column*/) override;

    bool LoadPrefix(InputStream* input, size_t rows) override;

    /// Loads column data from input stream.
    bool LoadBody(InputStream* input, size_t rows) override;

    /// Saves column prefix to output stream.
    void SavePrefix(OutputStream* output) override;

    /// Saves column data to output stream.
    void SaveBody(OutputStream* output) override;

    /// Clear column data.
    void Clear() override;

    /// Returns count of rows in the column.
    size_t Size() const override;

    /// Makes slice of current column, with compacted dictionary
    ColumnRef Slice(size_t begin, size_t len) const override;
    ColumnRef CloneEmpty() const override;
    void Swap(Column& other) override;
    ItemView GetItem(size_t index) const override;

    size_t GetDictionarySize() const;
    TypeRef GetNestedType() const;

protected:
    std::uint64_t getDictionaryIndex(std::uint64_t item_index) const;
    void appendIndex(std::uint64_t item_index);
    void removeLastIndex();
    ColumnRef GetDictionary();

    void AppendUnsafe(const ItemView &);

private:
    void Setup(ColumnRef dictionary_column);
    void AppendNullItem();
    void AppendDefaultItem();

public:
    static details::LowCardinalityHashKey computeHashKey(const ItemView &);
};

/** Type-aware wrapper that provides simple convenience interface for accessing/appending individual items.
 */
template <typename DictionaryColumnType>
class ColumnLowCardinalityT : public ColumnLowCardinality {

    DictionaryColumnType& typed_dictionary_;
    const Type::Code type_;

public:
    using WrappedColumnType = DictionaryColumnType;
    // Type this column takes as argument of Append and returns with At() and operator[]
    using ValueType = typename DictionaryColumnType::ValueType;

    explicit ColumnLowCardinalityT(ColumnLowCardinality&& col)
        : ColumnLowCardinality(std::move(col))
        ,  typed_dictionary_(dynamic_cast<DictionaryColumnType &>(*GetDictionary()))
        ,  type_(GetTypeCode(typed_dictionary_))
    {
    }

    template <typename ...Args>
    explicit ColumnLowCardinalityT(Args &&... args)
        : ColumnLowCardinalityT(std::make_shared<DictionaryColumnType>(std::forward<Args>(args)...))
    {}

    // Create LC<T> column from existing T-column, making a deep copy of all contents.
    explicit ColumnLowCardinalityT(std::shared_ptr<DictionaryColumnType> dictionary_col)
        : ColumnLowCardinality(dictionary_col)
        , typed_dictionary_(dynamic_cast<DictionaryColumnType &>(*GetDictionary()))
        , type_(GetTypeCode(typed_dictionary_))
    {}

    /// Extended interface to simplify reading/adding individual items.

    /// Returns element at given row number.
    inline ValueType At(size_t n) const {
        return typed_dictionary_.At(getDictionaryIndex(n));
    }

    /// Returns element at given row number.
    inline ValueType operator [] (size_t n) const {
        return typed_dictionary_[getDictionaryIndex(n)];
    }

    // so the non-virtual Append below doesn't shadow Append() from base class when compiled with older compilers.
    using ColumnLowCardinality::Append;

    inline void Append(const ValueType & value) {
        if constexpr (IsNullable<WrappedColumnType>) {
            if (value.has_value()) {
                AppendUnsafe(ItemView{type_, *value});
            } else {
                AppendUnsafe(ItemView{});
            }
        } else {
            AppendUnsafe(ItemView{type_, value});
        }
    }

    template <typename T>
    inline void AppendMany(const T& container) {
        for (const auto & item : container) {
            Append(item);
        }
    }

    /** Create a ColumnLowCardinalityT from a ColumnLowCardinality, without copying data and offsets, but by
     * 'stealing' those from `col`.
     *
     *  Ownership of column internals is transferred to returned object, original (argument) object
     *  MUST NOT BE USED IN ANY WAY, it is only safe to dispose it.
     *
     *  Throws an exception if `col` is of wrong type, it is safe to use original col in this case.
     *  This is a static method to make such conversion verbose.
     */
    static auto Wrap(ColumnLowCardinality&& col) {
        return std::make_shared<ColumnLowCardinalityT<WrappedColumnType>>(std::move(col));
    }

    static auto Wrap(Column&& col) { return Wrap(std::move(dynamic_cast<ColumnLowCardinality&&>(col))); }

    // Helper to simplify integration with other APIs
    static auto Wrap(ColumnRef&& col) { return Wrap(std::move(*col->AsStrict<ColumnLowCardinality>())); }

    ColumnRef Slice(size_t begin, size_t size) const override {
        return Wrap(ColumnLowCardinality::Slice(begin, size));
    }

    ColumnRef CloneEmpty() const override { return Wrap(ColumnLowCardinality::CloneEmpty()); }

private:

    template <typename T>
    static auto GetTypeCode(T& column) {
        if constexpr (IsNullable<T>) {
            return GetTypeCode(*column.Nested()->template AsStrict<typename T::NestedColumnType>());
        } else {
            return column.Type()->GetCode();
        }
    }
};

}


Question: What geometric data types are supported by the code?

Answer:
The code defines several type aliases using the ColumnGeo class template:
- ColumnPoint: Represents a Point column, which is a ColumnGeo of ColumnTupleT<ColumnFloat64, ColumnFloat64> with Type::Code::Point.
- ColumnRing: Represents a Ring column, which is a ColumnGeo of ColumnArrayT<ColumnPoint> with Type::Code::Ring.
- ColumnPolygon: Represents a Polygon column, which is a ColumnGeo of ColumnArrayT<ColumnRing> with Type::Code::Polygon.
- ColumnMultiPolygon: Represents a MultiPolygon column, which is a ColumnGeo of ColumnArrayT<ColumnPolygon> with Type::Code::MultiPolygon.

#pragma once

#include "array.h"
#include "column.h"
#include "numeric.h"
#include "tuple.h"

namespace clickhouse {

template <typename NestedColumnType, Type::Code type_code>
class ColumnGeo : public Column {
public:
    using ValueType = typename NestedColumnType::ValueType;

    ColumnGeo();

    explicit ColumnGeo(ColumnRef data);

    /// Appends one element to the end of column.
    template <typename T = ValueType>
    void Append(const T& value) {
        data_->Append(value);
    }

    /// Returns element at given row number.
    const ValueType At(size_t n) const;

    /// Returns element at given row number.
    inline const ValueType operator[](size_t n) const { return At(n); }

public:
    /// Increase the capacity of the column for large block insertion.
    void Reserve(size_t new_cap) override;

    /// Appends content of given column to the end of current one.
    void Append(ColumnRef column) override;

    /// Loads column data from input stream.
    bool LoadBody(InputStream* input, size_t rows) override;

    /// Saves column data to output stream.
    void SaveBody(OutputStream* output) override;

    /// Clear column data .
    void Clear() override;

    /// Returns count of rows in the column.
    size_t Size() const override;

    /// Makes slice of the current column.
    ColumnRef Slice(size_t begin, size_t len) const override;
    ColumnRef CloneEmpty() const override;
    void Swap(Column& other) override;

private:
    std::shared_ptr<NestedColumnType> data_;
};

// /**
//  * Represents a Point column.
//  */
using ColumnPoint = ColumnGeo<ColumnTupleT<ColumnFloat64, ColumnFloat64>, Type::Code::Point>;

/**
 * Represents a Ring column.
 */
using ColumnRing = ColumnGeo<ColumnArrayT<ColumnPoint>, Type::Code::Ring>;

/**
 * Represents a Polygon column.
 */
using ColumnPolygon = ColumnGeo<ColumnArrayT<ColumnRing>, Type::Code::Polygon>;

/**
 * Represents a MultiPolygon column.
 */
using ColumnMultiPolygon = ColumnGeo<ColumnArrayT<ColumnPolygon>, Type::Code::MultiPolygon>;

}  // namespace clickhouse


Question: How can you append an element to a ColumnGeo?

Answer:
The ColumnGeo class provides a template method Append() that allows appending an element to the end of the column. The method takes a single argument of type ValueType (which is derived from the NestedColumnType) or any type T that is convertible to ValueType. For example:
<code>
template <typename T = ValueType>
void Append(const T& value) {
    data_->Append(value);
}
</code>


Question: How can you access an element in a ColumnGeo?

Answer:
The ColumnGeo class provides two methods for accessing elements:
- At(size_t n): Returns the element at the given row number n.
- operator[](size_t n): Returns the element at the given row number n using the array subscript operator.
For example:
<code>
const ValueType At(size_t n) const;

inline const ValueType operator[](size_t n) const { return At(n); }
</code>


Question: How can you append the content of one ColumnGeo to another?

Answer:
The ColumnGeo class provides an Append(ColumnRef column) method that appends the content of the given column to the end of the current column. It is an overridden method from the base Column class. For example:
<code>
void Append(ColumnRef column) override;
</code>


Question: How can you clear the data of a ColumnGeo?

Answer:
The ColumnGeo class provides a Clear() method that clears the column data. It is an overridden method from the base Column class. For example:
<code>
void Clear() override;
</code>


Question: How do you construct a ProjectedIterator?

Answer:
To construct a ProjectedIterator, you need to provide an iterator and a unary function as arguments to the constructor. The constructor signature is:
inline ProjectedIterator(Iterator const& iterator, UnaryFunction functor)
It takes the underlying iterator by const reference and the unary function by value, and initializes the corresponding member variables iterator_ and functor_.

#pragma once

#include <iterator>
#include <type_traits>
#include <utility>

namespace clickhouse {

template <typename UnaryFunction, typename Iterator, typename Reference = decltype(std::declval<UnaryFunction>()(std::declval<Iterator>())),
          typename Value = std::decay_t<Reference>>
class ProjectedIterator {
public:
    using value_type        = Value;
    using reference         = Reference;
    using pointer           = Reference;
    using difference_type   = typename std::iterator_traits<Iterator>::difference_type;
    using iterator_category = typename std::iterator_traits<Iterator>::iterator_category;

    ProjectedIterator() = default;

    inline ProjectedIterator(Iterator const& iterator, UnaryFunction functor)
        : iterator_(iterator)
        , functor_(std::move(functor)) {
    }

    inline UnaryFunction functor() const { return functor; }

    inline Iterator const& base() const { return iterator_; }

    inline reference operator*() const { return functor_(iterator_); }

    inline ProjectedIterator& operator++() {
        ++iterator_;
        return *this;
    }

    inline ProjectedIterator& operator--() {
        --iterator_;
        return *this;
    }

    inline bool operator==(const ProjectedIterator& other) const {
        return this->iterator_ == other.iterator_;
    }

    inline bool operator!=(const ProjectedIterator& other) const {
        return !(*this == other);
    }

private:
    Iterator iterator_;
    UnaryFunction functor_;
};

}  // namespace clickhouse


Question: How do you increment and decrement a ProjectedIterator?

Answer:
The ProjectedIterator class overloads the increment (++) and decrement (--) operators to move the underlying iterator forward or backward. The operator implementations are:
<code>
inline ProjectedIterator& operator++() {
    ++iterator_;
    return *this;
}

inline ProjectedIterator& operator--() {
    --iterator_;
    return *this;
}
</code>
When the increment or decrement operator is called on a ProjectedIterator, it applies the corresponding operation to the underlying iterator (iterator_) and returns a reference to the updated ProjectedIterator.


Question: What are the possible values for the ConsoleOutput enum?

Answer:
The ConsoleOutput enum has three possible values, as defined in the code:

public enum ConsoleOutput {
  auto,
  rich,
  plain
}

The values are auto, rich, and plain.

/*
 * Copyright 2020 Google LLC.
 *
 * 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.
 */

package com.google.cloud.tools.jib.cli.logging;

public enum ConsoleOutput {
  auto,
  rich,
  plain
}


Question: What package is the ConsoleOutput enum defined in?

Answer:
The ConsoleOutput enum is defined in the package com.google.cloud.tools.jib.cli.logging, as indicated by this line:
package com.google.cloud.tools.jib.cli.logging;


Question: What do the different values of the ConsoleOutput enum represent?

Answer:
Based on the names, the values likely represent different modes for outputting to the console:
auto likely means the output format is automatically determined.
rich likely means the output uses rich formatting like colors or special characters.
plain likely means the output is plain text without any special formatting.
However, the specific behavior for each value is not defined in this file. The code that uses this enum would need to be consulted to determine the exact behavior.


Question: How does the UpdateChecker store the timestamp of the last update check?

Answer:
The UpdateChecker stores the timestamp of the last update check in a file named "lastUpdateCheck" in the configuration directory. After a successful update check, it writes the current timestamp to this file. This can be seen in the following code:
<code>
  Path lastUpdateCheckTemp =
      Files.createTempFile(configDir, LAST_UPDATE_CHECK_FILENAME, null);
  lastUpdateCheckTemp.toFile().deleteOnExit();
  Files.write(lastUpdateCheckTemp, Instant.now().toString().getBytes(StandardCharsets.UTF_8));
  Files.move(lastUpdateCheckTemp, lastUpdateCheck, StandardCopyOption.REPLACE_EXISTING);
</code>

/*
 * Copyright 2020 Google LLC.
 *
 * 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.
 */

package com.google.cloud.tools.jib.plugins.common;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.google.cloud.tools.jib.api.LogEvent;
import com.google.cloud.tools.jib.http.FailoverHttpClient;
import com.google.cloud.tools.jib.http.Request;
import com.google.cloud.tools.jib.http.Response;
import com.google.cloud.tools.jib.json.JsonTemplate;
import com.google.cloud.tools.jib.json.JsonTemplateMapper;
import com.google.cloud.tools.jib.plugins.common.globalconfig.GlobalConfig;
import com.google.common.annotations.VisibleForTesting;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.time.Duration;
import java.time.Instant;
import java.time.format.DateTimeParseException;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.function.Consumer;

/** Checks if Jib is up-to-date. */
public class UpdateChecker {

  private static final String LAST_UPDATE_CHECK_FILENAME = "lastUpdateCheck";

  /** JSON template for content downloaded during version check. */
  @JsonIgnoreProperties(ignoreUnknown = true)
  private static class VersionJsonTemplate implements JsonTemplate {
    private String latest = "";
  }

  /**
   * Begins checking for an update in a separate thread.
   *
   * @param executorService the {@link ExecutorService}
   * @param versionUrl the location to check for the latest version
   * @param toolName the tool name
   * @param toolVersion the tool version
   * @param log {@link Consumer} used to log messages
   * @return a new {@link UpdateChecker}
   */
  public static Future<Optional<String>> checkForUpdate(
      ExecutorService executorService,
      String versionUrl,
      String toolName,
      String toolVersion,
      Consumer<LogEvent> log) {
    return executorService.submit(
        () ->
            performUpdateCheck(
                GlobalConfig.getConfigDir(), toolVersion, versionUrl, toolName, log));
  }

  @VisibleForTesting
  static Optional<String> performUpdateCheck(
      Path configDir,
      String currentVersion,
      String versionUrl,
      String toolName,
      Consumer<LogEvent> log) {
    Path lastUpdateCheck = configDir.resolve(LAST_UPDATE_CHECK_FILENAME);

    try {
      // Check time of last update check
      if (Files.exists(lastUpdateCheck)) {
        try {
          String fileContents =
              new String(Files.readAllBytes(lastUpdateCheck), StandardCharsets.UTF_8);
          Instant modifiedTime = Instant.parse(fileContents);
          if (modifiedTime.plus(Duration.ofDays(1)).isAfter(Instant.now())) {
            return Optional.empty();
          }
        } catch (DateTimeParseException | IOException ex) {
          // If reading update time failed, file might be corrupt, so delete it
          log.accept(LogEvent.debug("Failed to read lastUpdateCheck; " + ex.getMessage()));
          Files.delete(lastUpdateCheck);
        }
      }

      // Check for update
      FailoverHttpClient httpClient = new FailoverHttpClient(true, false, ignored -> {});
      try {
        Response response =
            httpClient.get(
                new URL(versionUrl),
                Request.builder()
                    .setHttpTimeout(3000)
                    .setUserAgent("jib " + currentVersion + " " + toolName)
                    .build());
        VersionJsonTemplate version =
            JsonTemplateMapper.readJson(response.getBody(), VersionJsonTemplate.class);

        Path lastUpdateCheckTemp =
            Files.createTempFile(configDir, LAST_UPDATE_CHECK_FILENAME, null);
        lastUpdateCheckTemp.toFile().deleteOnExit();
        Files.write(lastUpdateCheckTemp, Instant.now().toString().getBytes(StandardCharsets.UTF_8));
        Files.move(lastUpdateCheckTemp, lastUpdateCheck, StandardCopyOption.REPLACE_EXISTING);

        if (currentVersion.equals(version.latest)) {
          return Optional.empty();
        }
        return Optional.of(version.latest);
      } finally {
        httpClient.shutDown();
      }

    } catch (IOException ex) {
      log.accept(LogEvent.debug("Update check failed; " + ex.getMessage()));
    }

    return Optional.empty();
  }

  /**
   * Returns the latest Jib version available if the check succeeded and the current version is
   * outdated, or returns {@code Optional.empty()} if the check was interrupted or did not determine
   * that a later version was available.
   *
   * @param updateMessageFuture the {@link Future} returned by {@link UpdateChecker#checkForUpdate}
   * @return the latest version, if found, else {@code Optional.empty()}.
   */
  public static Optional<String> finishUpdateCheck(Future<Optional<String>> updateMessageFuture) {
    if (updateMessageFuture.isDone()) {
      try {
        return updateMessageFuture.get();
      } catch (InterruptedException | ExecutionException ex) {
        // No need to restore the interrupted status. The intention here is to silently consume any
        // kind of error
      }
    }
    updateMessageFuture.cancel(true);
    return Optional.empty();
  }

  private UpdateChecker() {}
}


Question: What does the UpdateChecker return if the current version is up to date?

Answer:
If the UpdateChecker determines that the current version is equal to the latest version retrieved from the server, it returns Optional.empty(). This can be seen in the following code:
<code>
  if (currentVersion.equals(version.latest)) {
    return Optional.empty();
  }
</code>


Question: How does the DefaultCredentialRetrievers class handle credential helpers on Windows?

Answer:
On Windows, the DefaultCredentialRetrievers class will look for credential helper executables with a ".cmd" or ".exe" extension. This can be seen in the `testCredentialHelper_cmdExtension()` and `testCredentialHelper_exeExtension()` tests:
```java
properties.setProperty("os.name", "winDOWs");
List<CredentialRetriever> retrievers =
    new DefaultCredentialRetrievers(mockCredentialRetrieverFactory, properties, environment)
        .setCredentialHelper(pathWithoutCmd.toString())
        .asList();
```
When "os.name" is set to "winDOWs", it will look for the credential helper executable with a ".cmd" or ".exe" extension appended to the provided path.

/*
 * Copyright 2018 Google LLC.
 *
 * 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.
 */

package com.google.cloud.tools.jib.plugins.common;

import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import com.google.cloud.tools.jib.api.Credential;
import com.google.cloud.tools.jib.api.CredentialRetriever;
import com.google.cloud.tools.jib.frontend.CredentialRetrieverFactory;
import com.google.common.collect.ImmutableMap;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

/** Tests for {@link DefaultCredentialRetrievers}. */
@RunWith(MockitoJUnitRunner.class)
public class DefaultCredentialRetrieversTest {

  @Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder();

  @Mock private CredentialRetrieverFactory mockCredentialRetrieverFactory;
  @Mock private CredentialRetriever mockDockerCredentialHelperCredentialRetriever;
  @Mock private CredentialRetriever mockKnownCredentialRetriever;
  @Mock private CredentialRetriever mockInferredCredentialRetriever;
  @Mock private CredentialRetriever mockWellKnownCredentialHelpersCredentialRetriever;
  @Mock private CredentialRetriever mockXdgPrimaryCredentialRetriever;
  @Mock private CredentialRetriever mockEnvHomeXdgCredentialRetriever;
  @Mock private CredentialRetriever mockSystemHomeXdgCredentialRetriever;
  @Mock private CredentialRetriever mockDockerConfigEnvDockerConfigCredentialRetriever;
  @Mock private CredentialRetriever mockDockerConfigEnvKubernetesDockerConfigCredentialRetriever;
  @Mock private CredentialRetriever mockDockerConfigEnvLegacyDockerConfigCredentialRetriever;
  @Mock private CredentialRetriever mockSystemHomeDockerConfigCredentialRetriever;
  @Mock private CredentialRetriever mockSystemHomeKubernetesDockerConfigCredentialRetriever;
  @Mock private CredentialRetriever mockSystemHomeLegacyDockerConfigCredentialRetriever;
  @Mock private CredentialRetriever mockEnvHomeDockerConfigCredentialRetriever;
  @Mock private CredentialRetriever mockEnvHomeKubernetesDockerConfigCredentialRetriever;
  @Mock private CredentialRetriever mockEnvHomeLegacyDockerConfigCredentialRetriever;
  @Mock private CredentialRetriever mockApplicationDefaultCredentialRetriever;

  private Properties properties;
  private Map<String, String> environment;

  private final Credential knownCredential = Credential.from("username", "password");
  private final Credential inferredCredential = Credential.from("username2", "password2");

  @Before
  public void setUp() {
    properties = new Properties();
    properties.setProperty("os.name", "unknown");
    properties.setProperty("user.home", Paths.get("/system/home").toString());
    environment =
        ImmutableMap.of(
            "HOME",
            Paths.get("/env/home").toString(),
            "DOCKER_CONFIG",
            Paths.get("/docker_config").toString(),
            "XDG_RUNTIME_DIR",
            Paths.get("/run/user/1000").toString(),
            "XDG_CONFIG_HOME",
            Paths.get("/env/home/.config").toString());

    when(mockCredentialRetrieverFactory.dockerCredentialHelper(anyString()))
        .thenReturn(mockDockerCredentialHelperCredentialRetriever);
    when(mockCredentialRetrieverFactory.known(knownCredential, "credentialSource"))
        .thenReturn(mockKnownCredentialRetriever);
    when(mockCredentialRetrieverFactory.known(inferredCredential, "inferredCredentialSource"))
        .thenReturn(mockInferredCredentialRetriever);
    when(mockCredentialRetrieverFactory.wellKnownCredentialHelpers())
        .thenReturn(mockWellKnownCredentialHelpersCredentialRetriever);

    when(mockCredentialRetrieverFactory.dockerConfig(
            Paths.get("/run/user/1000/containers/auth.json")))
        .thenReturn(mockXdgPrimaryCredentialRetriever);
    when(mockCredentialRetrieverFactory.dockerConfig(
            Paths.get("/env/home/.config/containers/auth.json")))
        .thenReturn(mockEnvHomeXdgCredentialRetriever);

    when(mockCredentialRetrieverFactory.dockerConfig(
            Paths.get("/system/home/.config/containers/auth.json")))
        .thenReturn(mockSystemHomeXdgCredentialRetriever);

    when(mockCredentialRetrieverFactory.dockerConfig(Paths.get("/docker_config/config.json")))
        .thenReturn(mockDockerConfigEnvDockerConfigCredentialRetriever);
    when(mockCredentialRetrieverFactory.dockerConfig(Paths.get("/docker_config/.dockerconfigjson")))
        .thenReturn(mockDockerConfigEnvKubernetesDockerConfigCredentialRetriever);
    when(mockCredentialRetrieverFactory.legacyDockerConfig(Paths.get("/docker_config/.dockercfg")))
        .thenReturn(mockDockerConfigEnvLegacyDockerConfigCredentialRetriever);
    when(mockCredentialRetrieverFactory.dockerConfig(Paths.get("/system/home/.docker/config.json")))
        .thenReturn(mockSystemHomeDockerConfigCredentialRetriever);
    when(mockCredentialRetrieverFactory.dockerConfig(
            Paths.get("/system/home/.docker/.dockerconfigjson")))
        .thenReturn(mockSystemHomeKubernetesDockerConfigCredentialRetriever);
    when(mockCredentialRetrieverFactory.legacyDockerConfig(
            Paths.get("/system/home/.docker/.dockercfg")))
        .thenReturn(mockSystemHomeLegacyDockerConfigCredentialRetriever);
    when(mockCredentialRetrieverFactory.dockerConfig(Paths.get("/env/home/.docker/config.json")))
        .thenReturn(mockEnvHomeDockerConfigCredentialRetriever);
    when(mockCredentialRetrieverFactory.dockerConfig(
            Paths.get("/env/home/.docker/.dockerconfigjson")))
        .thenReturn(mockEnvHomeKubernetesDockerConfigCredentialRetriever);
    when(mockCredentialRetrieverFactory.legacyDockerConfig(
            Paths.get("/env/home/.docker/.dockercfg")))
        .thenReturn(mockEnvHomeLegacyDockerConfigCredentialRetriever);
    when(mockCredentialRetrieverFactory.googleApplicationDefaultCredentials())
        .thenReturn(mockApplicationDefaultCredentialRetriever);
  }

  @Test
  public void testAsList() throws FileNotFoundException {
    List<CredentialRetriever> retriever =
        new DefaultCredentialRetrievers(mockCredentialRetrieverFactory, properties, environment)
            .asList();
    assertThat(retriever)
        .containsExactly(
            mockXdgPrimaryCredentialRetriever,
            mockEnvHomeXdgCredentialRetriever,
            mockSystemHomeXdgCredentialRetriever,
            mockDockerConfigEnvDockerConfigCredentialRetriever,
            mockDockerConfigEnvKubernetesDockerConfigCredentialRetriever,
            mockDockerConfigEnvLegacyDockerConfigCredentialRetriever,
            mockSystemHomeDockerConfigCredentialRetriever,
            mockSystemHomeKubernetesDockerConfigCredentialRetriever,
            mockSystemHomeLegacyDockerConfigCredentialRetriever,
            mockEnvHomeDockerConfigCredentialRetriever,
            mockEnvHomeKubernetesDockerConfigCredentialRetriever,
            mockEnvHomeLegacyDockerConfigCredentialRetriever,
            mockWellKnownCredentialHelpersCredentialRetriever,
            mockApplicationDefaultCredentialRetriever)
        .inOrder();
  }

  @Test
  public void testAsList_all() throws FileNotFoundException {
    List<CredentialRetriever> retrievers =
        new DefaultCredentialRetrievers(mockCredentialRetrieverFactory, properties, environment)
            .setKnownCredential(knownCredential, "credentialSource")
            .setInferredCredential(inferredCredential, "inferredCredentialSource")
            .setCredentialHelper("credentialHelperSuffix")
            .asList();
    assertThat(retrievers)
        .containsExactly(
            mockKnownCredentialRetriever,
            mockDockerCredentialHelperCredentialRetriever,
            mockInferredCredentialRetriever,
            mockXdgPrimaryCredentialRetriever,
            mockEnvHomeXdgCredentialRetriever,
            mockSystemHomeXdgCredentialRetriever,
            mockDockerConfigEnvDockerConfigCredentialRetriever,
            mockDockerConfigEnvKubernetesDockerConfigCredentialRetriever,
            mockDockerConfigEnvLegacyDockerConfigCredentialRetriever,
            mockSystemHomeDockerConfigCredentialRetriever,
            mockSystemHomeKubernetesDockerConfigCredentialRetriever,
            mockSystemHomeLegacyDockerConfigCredentialRetriever,
            mockEnvHomeDockerConfigCredentialRetriever,
            mockEnvHomeKubernetesDockerConfigCredentialRetriever,
            mockEnvHomeLegacyDockerConfigCredentialRetriever,
            mockWellKnownCredentialHelpersCredentialRetriever,
            mockApplicationDefaultCredentialRetriever)
        .inOrder();

    verify(mockCredentialRetrieverFactory).known(knownCredential, "credentialSource");
    verify(mockCredentialRetrieverFactory).known(inferredCredential, "inferredCredentialSource");
    verify(mockCredentialRetrieverFactory)
        .dockerCredentialHelper("docker-credential-credentialHelperSuffix");
  }

  @Test
  public void testAsList_credentialHelperPath() throws IOException {
    Path fakeCredentialHelperPath = temporaryFolder.newFile("fake-credHelper").toPath();
    DefaultCredentialRetrievers credentialRetrievers =
        new DefaultCredentialRetrievers(mockCredentialRetrieverFactory, properties, environment)
            .setCredentialHelper(fakeCredentialHelperPath.toString());

    List<CredentialRetriever> retrievers = credentialRetrievers.asList();
    assertThat(retrievers)
        .containsExactly(
            mockDockerCredentialHelperCredentialRetriever,
            mockXdgPrimaryCredentialRetriever,
            mockEnvHomeXdgCredentialRetriever,
            mockSystemHomeXdgCredentialRetriever,
            mockDockerConfigEnvDockerConfigCredentialRetriever,
            mockDockerConfigEnvKubernetesDockerConfigCredentialRetriever,
            mockDockerConfigEnvLegacyDockerConfigCredentialRetriever,
            mockSystemHomeDockerConfigCredentialRetriever,
            mockSystemHomeKubernetesDockerConfigCredentialRetriever,
            mockSystemHomeLegacyDockerConfigCredentialRetriever,
            mockEnvHomeDockerConfigCredentialRetriever,
            mockEnvHomeKubernetesDockerConfigCredentialRetriever,
            mockEnvHomeLegacyDockerConfigCredentialRetriever,
            mockWellKnownCredentialHelpersCredentialRetriever,
            mockApplicationDefaultCredentialRetriever)
        .inOrder();
    verify(mockCredentialRetrieverFactory)
        .dockerCredentialHelper(fakeCredentialHelperPath.toString());

    Files.delete(fakeCredentialHelperPath);
    Exception ex = assertThrows(FileNotFoundException.class, credentialRetrievers::asList);
    assertThat(ex)
        .hasMessageThat()
        .isEqualTo("Specified credential helper was not found: " + fakeCredentialHelperPath);
  }

  @Test
  public void testDockerConfigRetrievers_undefinedHome() throws FileNotFoundException {
    List<CredentialRetriever> retrievers =
        new DefaultCredentialRetrievers(
                mockCredentialRetrieverFactory, new Properties(), new HashMap<>())
            .asList();
    assertThat(retrievers)
        .containsExactly(
            mockWellKnownCredentialHelpersCredentialRetriever,
            mockApplicationDefaultCredentialRetriever)
        .inOrder();
  }

  @Test
  public void testDockerConfigRetrievers_noDuplicateRetrievers() throws FileNotFoundException {
    properties.setProperty("user.home", Paths.get("/env/home").toString());
    List<CredentialRetriever> retrievers =
        new DefaultCredentialRetrievers(mockCredentialRetrieverFactory, properties, environment)
            .asList();
    assertThat(retrievers)
        .containsExactly(
            mockXdgPrimaryCredentialRetriever,
            mockEnvHomeXdgCredentialRetriever,
            mockDockerConfigEnvDockerConfigCredentialRetriever,
            mockDockerConfigEnvKubernetesDockerConfigCredentialRetriever,
            mockDockerConfigEnvLegacyDockerConfigCredentialRetriever,
            mockEnvHomeDockerConfigCredentialRetriever,
            mockEnvHomeKubernetesDockerConfigCredentialRetriever,
            mockEnvHomeLegacyDockerConfigCredentialRetriever,
            mockWellKnownCredentialHelpersCredentialRetriever,
            mockApplicationDefaultCredentialRetriever)
        .inOrder();

    environment =
        ImmutableMap.of(
            "HOME",
            Paths.get("/env/home").toString(),
            "DOCKER_CONFIG",
            Paths.get("/env/home/.docker").toString());
    retrievers =
        new DefaultCredentialRetrievers(mockCredentialRetrieverFactory, properties, environment)
            .asList();
    assertThat(retrievers)
        .containsExactly(
            mockEnvHomeXdgCredentialRetriever,
            mockEnvHomeDockerConfigCredentialRetriever,
            mockEnvHomeKubernetesDockerConfigCredentialRetriever,
            mockEnvHomeLegacyDockerConfigCredentialRetriever,
            mockWellKnownCredentialHelpersCredentialRetriever,
            mockApplicationDefaultCredentialRetriever)
        .inOrder();
  }

  @Test
  public void testCredentialHelper_cmdExtension() throws IOException {
    Path credHelper = temporaryFolder.newFile("foo.cmd").toPath();
    Path pathWithoutCmd = credHelper.getParent().resolve("foo");
    assertThat(credHelper).isEqualTo(pathWithoutCmd.getParent().resolve("foo.cmd"));

    DefaultCredentialRetrievers credentialRetrievers =
        new DefaultCredentialRetrievers(mockCredentialRetrieverFactory, properties, environment)
            .setCredentialHelper(pathWithoutCmd.toString());
    Exception ex = assertThrows(FileNotFoundException.class, credentialRetrievers::asList);
    assertThat(ex).hasMessageThat().startsWith("Specified credential helper was not found:");
    assertThat(ex).hasMessageThat().endsWith("foo");

    properties.setProperty("os.name", "winDOWs");
    List<CredentialRetriever> retrievers =
        new DefaultCredentialRetrievers(mockCredentialRetrieverFactory, properties, environment)
            .setCredentialHelper(pathWithoutCmd.toString())
            .asList();

    assertThat(retrievers)
        .containsExactly(
            mockDockerCredentialHelperCredentialRetriever,
            mockXdgPrimaryCredentialRetriever,
            mockEnvHomeXdgCredentialRetriever,
            mockSystemHomeXdgCredentialRetriever,
            mockDockerConfigEnvDockerConfigCredentialRetriever,
            mockDockerConfigEnvKubernetesDockerConfigCredentialRetriever,
            mockDockerConfigEnvLegacyDockerConfigCredentialRetriever,
            mockSystemHomeDockerConfigCredentialRetriever,
            mockSystemHomeKubernetesDockerConfigCredentialRetriever,
            mockSystemHomeLegacyDockerConfigCredentialRetriever,
            mockEnvHomeDockerConfigCredentialRetriever,
            mockEnvHomeKubernetesDockerConfigCredentialRetriever,
            mockEnvHomeLegacyDockerConfigCredentialRetriever,
            mockWellKnownCredentialHelpersCredentialRetriever,
            mockApplicationDefaultCredentialRetriever)
        .inOrder();
  }

  @Test
  public void testCredentialHelper_exeExtension() throws IOException {
    Path credHelper = temporaryFolder.newFile("foo.exe").toPath();
    Path pathWithoutExe = credHelper.getParent().resolve("foo");
    assertThat(credHelper).isEqualTo(pathWithoutExe.getParent().resolve("foo.exe"));

    DefaultCredentialRetrievers credentialRetrievers =
        new DefaultCredentialRetrievers(mockCredentialRetrieverFactory, properties, environment)
            .setCredentialHelper(pathWithoutExe.toString());
    Exception ex = assertThrows(FileNotFoundException.class, credentialRetrievers::asList);
    assertThat(ex).hasMessageThat().startsWith("Specified credential helper was not found:");
    assertThat(ex).hasMessageThat().endsWith("foo");

    properties.setProperty("os.name", "winDOWs");
    List<CredentialRetriever> retrievers =
        new DefaultCredentialRetrievers(mockCredentialRetrieverFactory, properties, environment)
            .setCredentialHelper(pathWithoutExe.toString())
            .asList();

    assertThat(retrievers)
        .containsExactly(
            mockDockerCredentialHelperCredentialRetriever,
            mockXdgPrimaryCredentialRetriever,
            mockEnvHomeXdgCredentialRetriever,
            mockSystemHomeXdgCredentialRetriever,
            mockDockerConfigEnvDockerConfigCredentialRetriever,
            mockDockerConfigEnvKubernetesDockerConfigCredentialRetriever,
            mockDockerConfigEnvLegacyDockerConfigCredentialRetriever,
            mockSystemHomeDockerConfigCredentialRetriever,
            mockSystemHomeKubernetesDockerConfigCredentialRetriever,
            mockSystemHomeLegacyDockerConfigCredentialRetriever,
            mockEnvHomeDockerConfigCredentialRetriever,
            mockEnvHomeKubernetesDockerConfigCredentialRetriever,
            mockEnvHomeLegacyDockerConfigCredentialRetriever,
            mockWellKnownCredentialHelpersCredentialRetriever,
            mockApplicationDefaultCredentialRetriever)
        .inOrder();
  }
}


Question: How does the DefaultCredentialRetrievers class avoid duplicate CredentialRetriever instances?

Answer:
The `testDockerConfigRetrievers_noDuplicateRetrievers()` test shows that the class avoids creating duplicate CredentialRetriever instances when there is overlap between the "user.home" system property and the "HOME" environment variable:
```java
properties.setProperty("user.home", Paths.get("/env/home").toString());
List<CredentialRetriever> retrievers =
    new DefaultCredentialRetrievers(mockCredentialRetrieverFactory, properties, environment)
        .asList();
```
With this setup, it only includes CredentialRetrievers for the "/env/home" paths, omitting the duplicates for "/system/home".

/*
 * Copyright 2018 Google LLC.
 *
 * 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.
 */

package com.google.cloud.tools.jib.plugins.common;

import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import com.google.cloud.tools.jib.api.Credential;
import com.google.cloud.tools.jib.api.CredentialRetriever;
import com.google.cloud.tools.jib.frontend.CredentialRetrieverFactory;
import com.google.common.collect.ImmutableMap;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

/** Tests for {@link DefaultCredentialRetrievers}. */
@RunWith(MockitoJUnitRunner.class)
public class DefaultCredentialRetrieversTest {

  @Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder();

  @Mock private CredentialRetrieverFactory mockCredentialRetrieverFactory;
  @Mock private CredentialRetriever mockDockerCredentialHelperCredentialRetriever;
  @Mock private CredentialRetriever mockKnownCredentialRetriever;
  @Mock private CredentialRetriever mockInferredCredentialRetriever;
  @Mock private CredentialRetriever mockWellKnownCredentialHelpersCredentialRetriever;
  @Mock private CredentialRetriever mockXdgPrimaryCredentialRetriever;
  @Mock private CredentialRetriever mockEnvHomeXdgCredentialRetriever;
  @Mock private CredentialRetriever mockSystemHomeXdgCredentialRetriever;
  @Mock private CredentialRetriever mockDockerConfigEnvDockerConfigCredentialRetriever;
  @Mock private CredentialRetriever mockDockerConfigEnvKubernetesDockerConfigCredentialRetriever;
  @Mock private CredentialRetriever mockDockerConfigEnvLegacyDockerConfigCredentialRetriever;
  @Mock private CredentialRetriever mockSystemHomeDockerConfigCredentialRetriever;
  @Mock private CredentialRetriever mockSystemHomeKubernetesDockerConfigCredentialRetriever;
  @Mock private CredentialRetriever mockSystemHomeLegacyDockerConfigCredentialRetriever;
  @Mock private CredentialRetriever mockEnvHomeDockerConfigCredentialRetriever;
  @Mock private CredentialRetriever mockEnvHomeKubernetesDockerConfigCredentialRetriever;
  @Mock private CredentialRetriever mockEnvHomeLegacyDockerConfigCredentialRetriever;
  @Mock private CredentialRetriever mockApplicationDefaultCredentialRetriever;

  private Properties properties;
  private Map<String, String> environment;

  private final Credential knownCredential = Credential.from("username", "password");
  private final Credential inferredCredential = Credential.from("username2", "password2");

  @Before
  public void setUp() {
    properties = new Properties();
    properties.setProperty("os.name", "unknown");
    properties.setProperty("user.home", Paths.get("/system/home").toString());
    environment =
        ImmutableMap.of(
            "HOME",
            Paths.get("/env/home").toString(),
            "DOCKER_CONFIG",
            Paths.get("/docker_config").toString(),
            "XDG_RUNTIME_DIR",
            Paths.get("/run/user/1000").toString(),
            "XDG_CONFIG_HOME",
            Paths.get("/env/home/.config").toString());

    when(mockCredentialRetrieverFactory.dockerCredentialHelper(anyString()))
        .thenReturn(mockDockerCredentialHelperCredentialRetriever);
    when(mockCredentialRetrieverFactory.known(knownCredential, "credentialSource"))
        .thenReturn(mockKnownCredentialRetriever);
    when(mockCredentialRetrieverFactory.known(inferredCredential, "inferredCredentialSource"))
        .thenReturn(mockInferredCredentialRetriever);
    when(mockCredentialRetrieverFactory.wellKnownCredentialHelpers())
        .thenReturn(mockWellKnownCredentialHelpersCredentialRetriever);

    when(mockCredentialRetrieverFactory.dockerConfig(
            Paths.get("/run/user/1000/containers/auth.json")))
        .thenReturn(mockXdgPrimaryCredentialRetriever);
    when(mockCredentialRetrieverFactory.dockerConfig(
            Paths.get("/env/home/.config/containers/auth.json")))
        .thenReturn(mockEnvHomeXdgCredentialRetriever);

    when(mockCredentialRetrieverFactory.dockerConfig(
            Paths.get("/system/home/.config/containers/auth.json")))
        .thenReturn(mockSystemHomeXdgCredentialRetriever);

    when(mockCredentialRetrieverFactory.dockerConfig(Paths.get("/docker_config/config.json")))
        .thenReturn(mockDockerConfigEnvDockerConfigCredentialRetriever);
    when(mockCredentialRetrieverFactory.dockerConfig(Paths.get("/docker_config/.dockerconfigjson")))
        .thenReturn(mockDockerConfigEnvKubernetesDockerConfigCredentialRetriever);
    when(mockCredentialRetrieverFactory.legacyDockerConfig(Paths.get("/docker_config/.dockercfg")))
        .thenReturn(mockDockerConfigEnvLegacyDockerConfigCredentialRetriever);
    when(mockCredentialRetrieverFactory.dockerConfig(Paths.get("/system/home/.docker/config.json")))
        .thenReturn(mockSystemHomeDockerConfigCredentialRetriever);
    when(mockCredentialRetrieverFactory.dockerConfig(
            Paths.get("/system/home/.docker/.dockerconfigjson")))
        .thenReturn(mockSystemHomeKubernetesDockerConfigCredentialRetriever);
    when(mockCredentialRetrieverFactory.legacyDockerConfig(
            Paths.get("/system/home/.docker/.dockercfg")))
        .thenReturn(mockSystemHomeLegacyDockerConfigCredentialRetriever);
    when(mockCredentialRetrieverFactory.dockerConfig(Paths.get("/env/home/.docker/config.json")))
        .thenReturn(mockEnvHomeDockerConfigCredentialRetriever);
    when(mockCredentialRetrieverFactory.dockerConfig(
            Paths.get("/env/home/.docker/.dockerconfigjson")))
        .thenReturn(mockEnvHomeKubernetesDockerConfigCredentialRetriever);
    when(mockCredentialRetrieverFactory.legacyDockerConfig(
            Paths.get("/env/home/.docker/.dockercfg")))
        .thenReturn(mockEnvHomeLegacyDockerConfigCredentialRetriever);
    when(mockCredentialRetrieverFactory.googleApplicationDefaultCredentials())
        .thenReturn(mockApplicationDefaultCredentialRetriever);
  }

  @Test
  public void testAsList() throws FileNotFoundException {
    List<CredentialRetriever> retriever =
        new DefaultCredentialRetrievers(mockCredentialRetrieverFactory, properties, environment)
            .asList();
    assertThat(retriever)
        .containsExactly(
            mockXdgPrimaryCredentialRetriever,
            mockEnvHomeXdgCredentialRetriever,
            mockSystemHomeXdgCredentialRetriever,
            mockDockerConfigEnvDockerConfigCredentialRetriever,
            mockDockerConfigEnvKubernetesDockerConfigCredentialRetriever,
            mockDockerConfigEnvLegacyDockerConfigCredentialRetriever,
            mockSystemHomeDockerConfigCredentialRetriever,
            mockSystemHomeKubernetesDockerConfigCredentialRetriever,
            mockSystemHomeLegacyDockerConfigCredentialRetriever,
            mockEnvHomeDockerConfigCredentialRetriever,
            mockEnvHomeKubernetesDockerConfigCredentialRetriever,
            mockEnvHomeLegacyDockerConfigCredentialRetriever,
            mockWellKnownCredentialHelpersCredentialRetriever,
            mockApplicationDefaultCredentialRetriever)
        .inOrder();
  }

  @Test
  public void testAsList_all() throws FileNotFoundException {
    List<CredentialRetriever> retrievers =
        new DefaultCredentialRetrievers(mockCredentialRetrieverFactory, properties, environment)
            .setKnownCredential(knownCredential, "credentialSource")
            .setInferredCredential(inferredCredential, "inferredCredentialSource")
            .setCredentialHelper("credentialHelperSuffix")
            .asList();
    assertThat(retrievers)
        .containsExactly(
            mockKnownCredentialRetriever,
            mockDockerCredentialHelperCredentialRetriever,
            mockInferredCredentialRetriever,
            mockXdgPrimaryCredentialRetriever,
            mockEnvHomeXdgCredentialRetriever,
            mockSystemHomeXdgCredentialRetriever,
            mockDockerConfigEnvDockerConfigCredentialRetriever,
            mockDockerConfigEnvKubernetesDockerConfigCredentialRetriever,
            mockDockerConfigEnvLegacyDockerConfigCredentialRetriever,
            mockSystemHomeDockerConfigCredentialRetriever,
            mockSystemHomeKubernetesDockerConfigCredentialRetriever,
            mockSystemHomeLegacyDockerConfigCredentialRetriever,
            mockEnvHomeDockerConfigCredentialRetriever,
            mockEnvHomeKubernetesDockerConfigCredentialRetriever,
            mockEnvHomeLegacyDockerConfigCredentialRetriever,
            mockWellKnownCredentialHelpersCredentialRetriever,
            mockApplicationDefaultCredentialRetriever)
        .inOrder();

    verify(mockCredentialRetrieverFactory).known(knownCredential, "credentialSource");
    verify(mockCredentialRetrieverFactory).known(inferredCredential, "inferredCredentialSource");
    verify(mockCredentialRetrieverFactory)
        .dockerCredentialHelper("docker-credential-credentialHelperSuffix");
  }

  @Test
  public void testAsList_credentialHelperPath() throws IOException {
    Path fakeCredentialHelperPath = temporaryFolder.newFile("fake-credHelper").toPath();
    DefaultCredentialRetrievers credentialRetrievers =
        new DefaultCredentialRetrievers(mockCredentialRetrieverFactory, properties, environment)
            .setCredentialHelper(fakeCredentialHelperPath.toString());

    List<CredentialRetriever> retrievers = credentialRetrievers.asList();
    assertThat(retrievers)
        .containsExactly(
            mockDockerCredentialHelperCredentialRetriever,
            mockXdgPrimaryCredentialRetriever,
            mockEnvHomeXdgCredentialRetriever,
            mockSystemHomeXdgCredentialRetriever,
            mockDockerConfigEnvDockerConfigCredentialRetriever,
            mockDockerConfigEnvKubernetesDockerConfigCredentialRetriever,
            mockDockerConfigEnvLegacyDockerConfigCredentialRetriever,
            mockSystemHomeDockerConfigCredentialRetriever,
            mockSystemHomeKubernetesDockerConfigCredentialRetriever,
            mockSystemHomeLegacyDockerConfigCredentialRetriever,
            mockEnvHomeDockerConfigCredentialRetriever,
            mockEnvHomeKubernetesDockerConfigCredentialRetriever,
            mockEnvHomeLegacyDockerConfigCredentialRetriever,
            mockWellKnownCredentialHelpersCredentialRetriever,
            mockApplicationDefaultCredentialRetriever)
        .inOrder();
    verify(mockCredentialRetrieverFactory)
        .dockerCredentialHelper(fakeCredentialHelperPath.toString());

    Files.delete(fakeCredentialHelperPath);
    Exception ex = assertThrows(FileNotFoundException.class, credentialRetrievers::asList);
    assertThat(ex)
        .hasMessageThat()
        .isEqualTo("Specified credential helper was not found: " + fakeCredentialHelperPath);
  }

  @Test
  public void testDockerConfigRetrievers_undefinedHome() throws FileNotFoundException {
    List<CredentialRetriever> retrievers =
        new DefaultCredentialRetrievers(
                mockCredentialRetrieverFactory, new Properties(), new HashMap<>())
            .asList();
    assertThat(retrievers)
        .containsExactly(
            mockWellKnownCredentialHelpersCredentialRetriever,
            mockApplicationDefaultCredentialRetriever)
        .inOrder();
  }

  @Test
  public void testDockerConfigRetrievers_noDuplicateRetrievers() throws FileNotFoundException {
    properties.setProperty("user.home", Paths.get("/env/home").toString());
    List<CredentialRetriever> retrievers =
        new DefaultCredentialRetrievers(mockCredentialRetrieverFactory, properties, environment)
            .asList();
    assertThat(retrievers)
        .containsExactly(
            mockXdgPrimaryCredentialRetriever,
            mockEnvHomeXdgCredentialRetriever,
            mockDockerConfigEnvDockerConfigCredentialRetriever,
            mockDockerConfigEnvKubernetesDockerConfigCredentialRetriever,
            mockDockerConfigEnvLegacyDockerConfigCredentialRetriever,
            mockEnvHomeDockerConfigCredentialRetriever,
            mockEnvHomeKubernetesDockerConfigCredentialRetriever,
            mockEnvHomeLegacyDockerConfigCredentialRetriever,
            mockWellKnownCredentialHelpersCredentialRetriever,
            mockApplicationDefaultCredentialRetriever)
        .inOrder();

    environment =
        ImmutableMap.of(
            "HOME",
            Paths.get("/env/home").toString(),
            "DOCKER_CONFIG",
            Paths.get("/env/home/.docker").toString());
    retrievers =
        new DefaultCredentialRetrievers(mockCredentialRetrieverFactory, properties, environment)
            .asList();
    assertThat(retrievers)
        .containsExactly(
            mockEnvHomeXdgCredentialRetriever,
            mockEnvHomeDockerConfigCredentialRetriever,
            mockEnvHomeKubernetesDockerConfigCredentialRetriever,
            mockEnvHomeLegacyDockerConfigCredentialRetriever,
            mockWellKnownCredentialHelpersCredentialRetriever,
            mockApplicationDefaultCredentialRetriever)
        .inOrder();
  }

  @Test
  public void testCredentialHelper_cmdExtension() throws IOException {
    Path credHelper = temporaryFolder.newFile("foo.cmd").toPath();
    Path pathWithoutCmd = credHelper.getParent().resolve("foo");
    assertThat(credHelper).isEqualTo(pathWithoutCmd.getParent().resolve("foo.cmd"));

    DefaultCredentialRetrievers credentialRetrievers =
        new DefaultCredentialRetrievers(mockCredentialRetrieverFactory, properties, environment)
            .setCredentialHelper(pathWithoutCmd.toString());
    Exception ex = assertThrows(FileNotFoundException.class, credentialRetrievers::asList);
    assertThat(ex).hasMessageThat().startsWith("Specified credential helper was not found:");
    assertThat(ex).hasMessageThat().endsWith("foo");

    properties.setProperty("os.name", "winDOWs");
    List<CredentialRetriever> retrievers =
        new DefaultCredentialRetrievers(mockCredentialRetrieverFactory, properties, environment)
            .setCredentialHelper(pathWithoutCmd.toString())
            .asList();

    assertThat(retrievers)
        .containsExactly(
            mockDockerCredentialHelperCredentialRetriever,
            mockXdgPrimaryCredentialRetriever,
            mockEnvHomeXdgCredentialRetriever,
            mockSystemHomeXdgCredentialRetriever,
            mockDockerConfigEnvDockerConfigCredentialRetriever,
            mockDockerConfigEnvKubernetesDockerConfigCredentialRetriever,
            mockDockerConfigEnvLegacyDockerConfigCredentialRetriever,
            mockSystemHomeDockerConfigCredentialRetriever,
            mockSystemHomeKubernetesDockerConfigCredentialRetriever,
            mockSystemHomeLegacyDockerConfigCredentialRetriever,
            mockEnvHomeDockerConfigCredentialRetriever,
            mockEnvHomeKubernetesDockerConfigCredentialRetriever,
            mockEnvHomeLegacyDockerConfigCredentialRetriever,
            mockWellKnownCredentialHelpersCredentialRetriever,
            mockApplicationDefaultCredentialRetriever)
        .inOrder();
  }

  @Test
  public void testCredentialHelper_exeExtension() throws IOException {
    Path credHelper = temporaryFolder.newFile("foo.exe").toPath();
    Path pathWithoutExe = credHelper.getParent().resolve("foo");
    assertThat(credHelper).isEqualTo(pathWithoutExe.getParent().resolve("foo.exe"));

    DefaultCredentialRetrievers credentialRetrievers =
        new DefaultCredentialRetrievers(mockCredentialRetrieverFactory, properties, environment)
            .setCredentialHelper(pathWithoutExe.toString());
    Exception ex = assertThrows(FileNotFoundException.class, credentialRetrievers::asList);
    assertThat(ex).hasMessageThat().startsWith("Specified credential helper was not found:");
    assertThat(ex).hasMessageThat().endsWith("foo");

    properties.setProperty("os.name", "winDOWs");
    List<CredentialRetriever> retrievers =
        new DefaultCredentialRetrievers(mockCredentialRetrieverFactory, properties, environment)
            .setCredentialHelper(pathWithoutExe.toString())
            .asList();

    assertThat(retrievers)
        .containsExactly(
            mockDockerCredentialHelperCredentialRetriever,
            mockXdgPrimaryCredentialRetriever,
            mockEnvHomeXdgCredentialRetriever,
            mockSystemHomeXdgCredentialRetriever,
            mockDockerConfigEnvDockerConfigCredentialRetriever,
            mockDockerConfigEnvKubernetesDockerConfigCredentialRetriever,
            mockDockerConfigEnvLegacyDockerConfigCredentialRetriever,
            mockSystemHomeDockerConfigCredentialRetriever,
            mockSystemHomeKubernetesDockerConfigCredentialRetriever,
            mockSystemHomeLegacyDockerConfigCredentialRetriever,
            mockEnvHomeDockerConfigCredentialRetriever,
            mockEnvHomeKubernetesDockerConfigCredentialRetriever,
            mockEnvHomeLegacyDockerConfigCredentialRetriever,
            mockWellKnownCredentialHelpersCredentialRetriever,
            mockApplicationDefaultCredentialRetriever)
        .inOrder();
  }
}


Question: What does the `ReproducibleImageTest` test class verify?

Answer:
According to the class Javadoc comment, `ReproducibleImageTest` verifies that the created image has explicit directory structures, default timestamps, permissions, and file orderings:
<code>/**
 * Verify that created image has explicit directory structures, default timestamps, permissions, and
 * file orderings.
 */
public class ReproducibleImageTest { ... }
</code>

/*
 * Copyright 2019 Google LLC.
 *
 * 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.
 */

package com.google.cloud.tools.jib.api;

import static com.google.common.truth.Truth.assertThat;

import com.google.cloud.tools.jib.api.buildplan.AbsoluteUnixPath;
import com.google.cloud.tools.jib.api.buildplan.FileEntriesLayer;
import com.google.cloud.tools.jib.api.buildplan.FilePermissions;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Multimap;
import com.google.common.io.CharStreams;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.function.BiConsumer;
import java.util.zip.GZIPInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

/**
 * Verify that created image has explicit directory structures, default timestamps, permissions, and
 * file orderings.
 */
public class ReproducibleImageTest {

  @ClassRule public static final TemporaryFolder imageLocation = new TemporaryFolder();

  private static File imageTar;

  @BeforeClass
  public static void createImage()
      throws InvalidImageReferenceException, InterruptedException, CacheDirectoryCreationException,
          IOException, RegistryException, ExecutionException {

    Path root = imageLocation.getRoot().toPath();
    Path fileA = Files.createFile(root.resolve("fileA.txt"));
    Path fileB = Files.createFile(root.resolve("fileB.txt"));
    Path fileC = Files.createFile(root.resolve("fileC.txt"));
    Path subdir = Files.createDirectory(root.resolve("dir"));
    Path subsubdir = Files.createDirectory(subdir.resolve("subdir"));
    Files.createFile(subdir.resolve("fileD.txt"));
    Files.createFile(subsubdir.resolve("fileE.txt"));

    imageTar = new File(imageLocation.getRoot(), "image.tar");
    Containerizer containerizer =
        Containerizer.to(TarImage.at(imageTar.toPath()).named("jib-core/reproducible"));

    Jib.fromScratch()
        .setEntrypoint("echo", "Hello World")
        .addLayer(ImmutableList.of(fileA), AbsoluteUnixPath.get("/app"))
        // layer with out-of-order files
        .addLayer(ImmutableList.of(fileC, fileB), "/app")
        .addFileEntriesLayer(
            FileEntriesLayer.builder()
                .addEntryRecursive(subdir, AbsoluteUnixPath.get("/app"))
                .build())
        .containerize(containerizer);
  }

  @Test
  public void testTarballStructure() throws IOException {
    // known content should produce known results
    List<String> actual = new ArrayList<>();
    try (TarArchiveInputStream input =
        new TarArchiveInputStream(Files.newInputStream(imageTar.toPath()))) {
      TarArchiveEntry imageEntry;
      while ((imageEntry = input.getNextTarEntry()) != null) {
        actual.add(imageEntry.getName());
      }
    }

    assertThat(actual)
        .containsExactly(
            "c46572ef74f58d95e44dd36c1fbdfebd3752e8b56a794a13c11cfed35a1a6e1c.tar.gz",
            "6d2763b0f3940d324ea6b55386429e5b173899608abf7d1bff62e25dd2e4dcea.tar.gz",
            "530c1954a2b087d0b989895ea56435c9dc739a973f2d2b6cb9bb98e55bbea7ac.tar.gz",
            "config.json",
            "manifest.json")
        .inOrder();
  }

  @Test
  public void testManifest() throws IOException {
    String expectedManifest =
        "[{\"Config\":\"config.json\",\"RepoTags\":[\"jib-core/reproducible:latest\"],"
            + "\"Layers\":[\"c46572ef74f58d95e44dd36c1fbdfebd3752e8b56a794a13c11cfed35a1a6e1c.tar.gz\",\"6d2763b0f3940d324ea6b55386429e5b173899608abf7d1bff62e25dd2e4dcea.tar.gz\",\"530c1954a2b087d0b989895ea56435c9dc739a973f2d2b6cb9bb98e55bbea7ac.tar.gz\"]}]";
    String generatedManifest = extractFromTarFileAsString(imageTar, "manifest.json");
    assertThat(generatedManifest).isEqualTo(expectedManifest);
  }

  @Test
  public void testConfiguration() throws IOException {
    String expectedConfig =
        "{\"created\":\"1970-01-01T00:00:00Z\",\"architecture\":\"amd64\",\"os\":\"linux\","
            + "\"config\":{\"Env\":[],\"Entrypoint\":[\"echo\",\"Hello World\"],\"ExposedPorts\":{},\"Labels\":{},\"Volumes\":{}},"
            + "\"history\":[{\"created\":\"1970-01-01T00:00:00Z\",\"author\":\"Jib\",\"created_by\":\"jib-core:null\",\"comment\":\"\"},{\"created\":\"1970-01-01T00:00:00Z\",\"author\":\"Jib\",\"created_by\":\"jib-core:null\",\"comment\":\"\"},{\"created\":\"1970-01-01T00:00:00Z\",\"author\":\"Jib\",\"created_by\":\"jib-core:null\",\"comment\":\"\"}],"
            + "\"rootfs\":{\"type\":\"layers\",\"diff_ids\":[\"sha256:18e4f44e6d1835bd968339b166057bd17ab7d4cbb56dc7262a5cafea7cf8d405\",\"sha256:13369c34f073f2b9c1fa6431e23d925f1a8eac65b1726c8cc8fcc2596c69b414\",\"sha256:4f92c507112d7880ca0f504ef8272b7fdee107263270125036a260a741565923\"]}}";
    String generatedConfig = extractFromTarFileAsString(imageTar, "config.json");
    assertThat(generatedConfig).isEqualTo(expectedConfig);
  }

  @Test
  public void testImageLayout() throws IOException {
    Set<String> paths = new HashSet<>();
    layerEntriesDo(
        (layerName, layerEntry) -> {
          if (layerEntry.isFile()) {
            paths.add(layerEntry.getName());
          }
        });
    assertThat(paths)
        .containsExactly(
            "app/fileA.txt",
            "app/fileB.txt",
            "app/fileC.txt",
            "app/fileD.txt",
            "app/subdir/fileE.txt");
  }

  @Test
  public void testAllFileAndDirectories() throws IOException {
    layerEntriesDo(
        (layerName, layerEntry) ->
            assertThat(layerEntry.isFile() || layerEntry.isDirectory()).isTrue());
  }

  @Test
  public void testTimestampsEpochPlus1s() throws IOException {
    layerEntriesDo(
        (layerName, layerEntry) -> {
          Instant modificationTime = layerEntry.getLastModifiedDate().toInstant();
          assertThat(modificationTime).isEqualTo(Instant.ofEpochSecond(1));
        });
  }

  @Test
  public void testPermissions() throws IOException {
    assertThat(FilePermissions.DEFAULT_FILE_PERMISSIONS.getPermissionBits()).isEqualTo(0644);
    assertThat(FilePermissions.DEFAULT_FOLDER_PERMISSIONS.getPermissionBits()).isEqualTo(0755);
    layerEntriesDo(
        (layerName, layerEntry) -> {
          if (layerEntry.isFile()) {
            assertThat(layerEntry.getMode() & 0777).isEqualTo(0644);
          } else if (layerEntry.isDirectory()) {
            assertThat(layerEntry.getMode() & 0777).isEqualTo(0755);
          }
        });
  }

  @Test
  public void testNoImplicitParentDirectories() throws IOException {
    Set<String> directories = new HashSet<>();
    layerEntriesDo(
        (layerName, layerEntry) -> {
          String entryPath = layerEntry.getName();
          if (layerEntry.isDirectory()) {
            assertThat(entryPath.endsWith("/")).isTrue();
            entryPath = entryPath.substring(0, entryPath.length() - 1);
          }

          int lastSlashPosition = entryPath.lastIndexOf('/');
          String parent = entryPath.substring(0, Math.max(0, lastSlashPosition));
          if (!parent.isEmpty()) {
            assertThat(directories.contains(parent)).isTrue();
          }
          if (layerEntry.isDirectory()) {
            directories.add(entryPath);
          }
        });
  }

  @Test
  public void testFileOrdering() throws IOException {
    Multimap<String, String> layerPaths = ArrayListMultimap.create();
    layerEntriesDo((layerName, layerEntry) -> layerPaths.put(layerName, layerEntry.getName()));
    for (Collection<String> paths : layerPaths.asMap().values()) {
      List<String> sorted = new ArrayList<>(paths);
      // ReproducibleLayerBuilder sorts by TarArchiveEntry::getName()
      Collections.sort(sorted);
      assertThat(paths).containsExactlyElementsIn(sorted).inOrder();
    }
  }

  private void layerEntriesDo(BiConsumer<String, TarArchiveEntry> layerConsumer)
      throws IOException {

    try (TarArchiveInputStream input =
        new TarArchiveInputStream(Files.newInputStream(imageTar.toPath()))) {
      TarArchiveEntry imageEntry;
      while ((imageEntry = input.getNextTarEntry()) != null) {
        String imageEntryName = imageEntry.getName();
        // assume all .tar.gz files are layers
        if (imageEntry.isFile() && imageEntryName.endsWith(".tar.gz")) {
          @SuppressWarnings("resource") // must not close sub-streams
          TarArchiveInputStream layer = new TarArchiveInputStream(new GZIPInputStream(input));
          TarArchiveEntry layerEntry;
          while ((layerEntry = layer.getNextTarEntry()) != null) {
            layerConsumer.accept(imageEntryName, layerEntry);
          }
        }
      }
    }
  }

  private static String extractFromTarFileAsString(File tarFile, String filename)
      throws IOException {
    try (TarArchiveInputStream input =
        new TarArchiveInputStream(Files.newInputStream(tarFile.toPath()))) {
      TarArchiveEntry imageEntry;
      while ((imageEntry = input.getNextTarEntry()) != null) {
        if (filename.equals(imageEntry.getName())) {
          return CharStreams.toString(new InputStreamReader(input, StandardCharsets.UTF_8));
        }
      }
    }
    throw new AssertionError("file not found: " + filename);
  }
}


Question: How does the `createImage()` method create the test image?

Answer:
The `createImage()` method performs the following steps to create the test image:
1. Creates a temporary directory using `TemporaryFolder` and creates several test files and directories within it.
2. Configures a `Containerizer` to build a tarball image named "jib-core/reproducible" using `TarImage`.
3. Builds a container image using `Jib.fromScratch()` by setting the entrypoint, adding layers with the test files, and containerizing with the configured `Containerizer`.
<code>
Containerizer containerizer =
        Containerizer.to(TarImage.at(imageTar.toPath()).named("jib-core/reproducible"));

Jib.fromScratch()
    .setEntrypoint("echo", "Hello World")
    .addLayer(ImmutableList.of(fileA), AbsoluteUnixPath.get("/app"))
    // layer with out-of-order files
    .addLayer(ImmutableList.of(fileC, fileB), "/app")
    .addFileEntriesLayer(
        FileEntriesLayer.builder()
            .addEntryRecursive(subdir, AbsoluteUnixPath.get("/app"))
            .build())
    .containerize(containerizer);
</code>


Question: What is the expected tarball structure and how is it verified in `testTarballStructure()`?

Answer:
The `testTarballStructure()` method verifies the expected tarball structure by reading the generated `image.tar` file and asserting that it contains the following entries in order:
<code>
assertThat(actual)
    .containsExactly(
        "c46572ef74f58d95e44dd36c1fbdfebd3752e8b56a794a13c11cfed35a1a6e1c.tar.gz",
        "6d2763b0f3940d324ea6b55386429e5b173899608abf7d1bff62e25dd2e4dcea.tar.gz",
        "530c1954a2b087d0b989895ea56435c9dc739a973f2d2b6cb9bb98e55bbea7ac.tar.gz",
        "config.json",
        "manifest.json")
    .inOrder();
</code>


Question: What package does the HelloWorld class belong to?

Answer:
The HelloWorld class belongs to the com.test package, as specified by this line at the top of the file:
<code>
package com.test;
</code>

/*
 * Copyright 2018 Google LLC.
 *
 * 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.
 */

package com.test;

public class HelloWorld {
  public static void main(String[] args) {
    System.out.println("Hello world");
  }
}


Question: What license is this code released under?

Answer:
The code is licensed under the Apache License, Version 2.0, as stated in the code comments at the top of the file:
<code>
/*
 * Copyright 2018 Google LLC.
 *
 * 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.
 */
</code>


Question: What year was this code copyrighted?

Answer:
According to the copyright notice at the top of the file, this code was copyrighted in 2018:
<code>
/*
 * Copyright 2018 Google LLC.
 */
</code>


Question: What company owns the copyright to this code?

Answer:
The copyright notice states that Google LLC owns the copyright to this code:
<code>
/*
 * Copyright 2018 Google LLC.
 */
</code>