<commit_before>// Copyright (c) 2016 The WebM project authors. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS.  All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
#include "webm2pes.h"

#include <cstdint>
#include <cstdio>
#include <limits>
#include <vector>

#include "gtest/gtest.h"

#include "common/libwebm_utils.h"
#include "testing/test_util.h"

namespace {

struct PesOptionalHeader {
  int marker = 0;
  int scrambling = 0;
  int priority = 0;
  int data_alignment = 0;
  int copyright = 0;
  int original = 0;
  int has_pts = 0;
  int has_dts = 0;
  int unused_fields = 0;
  int remaining_size = 0;
  int pts_dts_flag = 0;
  std::uint64_t pts = 0;
  int stuffing_byte = 0;
};

struct BcmvHeader {
  BcmvHeader() = default;
  ~BcmvHeader() = default;
  BcmvHeader(const BcmvHeader&) = delete;
  BcmvHeader(BcmvHeader&&) = delete;

  // Convenience ctor for quick validation of expected values via operator==
  // after parsing input.
  explicit BcmvHeader(std::uint32_t len) : length(len) {
    id[0] = 'B';
    id[1] = 'C';
    id[2] = 'M';
    id[3] = 'V';
  }

  bool operator==(const BcmvHeader& other) const {
    return (other.length == length && other.id[0] == id[0] &&
            other.id[1] == id[1] && other.id[2] == id[2] &&
            other.id[3] == id[3]);
  }

  bool Valid() const {
    return (length > 0 && length <= std::numeric_limits<std::uint16_t>::max() &&
            id[0] == 'B' && id[1] == 'C' && id[2] == 'M' && id[3] == 'V');
  }

  char id[4] = {0};
  std::uint32_t length = 0;
};

struct PesHeader {
  std::uint16_t packet_length = 0;
  PesOptionalHeader opt_header;
  BcmvHeader bcmv_header;
};

class Webm2PesTests : public ::testing::Test {
 public:
  typedef std::vector<std::uint8_t> PesFileData;

  enum ParseState {
    kParsePesHeader,
    kParsePesOptionalHeader,
    kParseBcmvHeader,
  };

  // Constants for validating known values from input data.
  const std::uint8_t kMinVideoStreamId = 0xE0;
  const std::uint8_t kMaxVideoStreamId = 0xEF;
  const std::size_t kPesHeaderSize = 6;
  const std::size_t kPesOptionalHeaderStartOffset = kPesHeaderSize;
  const std::size_t kPesOptionalHeaderSize = 9;
  const int kPesOptionalHeaderMarkerValue = 0x2;
  const std::size_t kWebm2PesOptHeaderRemainingSize = 6;
  const std::size_t kBcmvHeaderSize = 10;

  Webm2PesTests() : read_pos_(0), parse_state_(kParsePesHeader) {}

  bool CreateAndLoadTestInput() {
    libwebm::Webm2Pes converter(input_file_name_, temp_file_name_.name());
    EXPECT_TRUE(converter.ConvertToFile());
    pes_file_size_ = libwebm::test::GetFileSize(pes_file_name());
    EXPECT_GT(pes_file_size_, 0);
    pes_file_data_.reserve(pes_file_size_);
    EXPECT_EQ(pes_file_size_, pes_file_data_.capacity());
    libwebm::FilePtr file = libwebm::FilePtr(
        std::fopen(pes_file_name().c_str(), "rb"), libwebm::FILEDeleter());
    EXPECT_EQ(std::fread(&pes_file_data_[0], 1, pes_file_size_, file.get()),
              pes_file_size_);
    read_pos_ = 0;
    parse_state_ = kParsePesHeader;
    return true;
  }

  bool VerifyPacketStartCode() {
    // PES packets all start with the byte sequence 0x0 0x0 0x1.
    if (pes_file_data_[read_pos_] != 0 || pes_file_data_[read_pos_ + 1] != 0 ||
        pes_file_data_[read_pos_ + 2] != 1) {
      return false;
    }
    return true;
  }

  std::uint8_t ReadStreamId() { return pes_file_data_[read_pos_ + 3]; }

  std::uint16_t ReadPacketLength() {
    // Read and byte swap 16 bit big endian length.
    return (pes_file_data_[read_pos_ + 4] << 8) | pes_file_data_[read_pos_ + 5];
  }

  void ParsePesHeader(PesHeader* header) {
    ASSERT_TRUE(header != nullptr);
    EXPECT_EQ(kParsePesHeader, parse_state_);
    EXPECT_TRUE(VerifyPacketStartCode());
    // PES Video stream IDs start at E0.
    EXPECT_GE(ReadStreamId(), kMinVideoStreamId);
    EXPECT_LE(ReadStreamId(), kMaxVideoStreamId);
    header->packet_length = ReadPacketLength();
    read_pos_ += kPesHeaderSize;
    parse_state_ = kParsePesOptionalHeader;
  }

  // Parses a PES optional header.
  // https://en.wikipedia.org/wiki/Packetized_elementary_stream
  // TODO(tomfinegan): Make these masks constants.
  void ParsePesOptionalHeader(PesOptionalHeader* header) {
    ASSERT_TRUE(header != nullptr);
    EXPECT_EQ(kParsePesOptionalHeader, parse_state_);
    std::size_t offset = read_pos_;
    EXPECT_LT(offset, pes_file_size_);

    header->marker = (pes_file_data_[offset] & 0x80) >> 6;
    header->scrambling = (pes_file_data_[offset] & 0x30) >> 4;
    header->priority = (pes_file_data_[offset] & 0x8) >> 3;
    header->data_alignment = (pes_file_data_[offset] & 0xc) >> 2;
    header->copyright = (pes_file_data_[offset] & 0x2) >> 1;
    header->original = pes_file_data_[offset] & 0x1;

    offset++;
    header->has_pts = (pes_file_data_[offset] & 0x80) >> 7;
    header->has_dts = (pes_file_data_[offset] & 0x40) >> 6;
    header->unused_fields = pes_file_data_[offset] & 0x3f;

    offset++;
    header->remaining_size = pes_file_data_[offset];
    EXPECT_EQ(kWebm2PesOptHeaderRemainingSize, header->remaining_size);

    int bytes_left = header->remaining_size;

    if (header->has_pts) {
      // Read PTS markers. Format:
      // PTS: 5 bytes
      //   4 bits (flag: PTS present, but no DTS): 0x2 ('0010')
      //   36 bits (90khz PTS):
      //     top 3 bits
      //     marker ('1')
      //     middle 15 bits
      //     marker ('1')
      //     bottom 15 bits
      //     marker ('1')
      // TODO(tomfinegan): Extract some golden timestamp values and actually
      // read the timestamp.
      offset++;
      header->pts_dts_flag = (pes_file_data_[offset] & 0x20) >> 4;
      // Check the marker bits.
      int marker_bit = pes_file_data_[offset] & 1;
      EXPECT_EQ(1, marker_bit);
      offset += 2;
      marker_bit = pes_file_data_[offset] & 1;
      EXPECT_EQ(1, marker_bit);
      offset += 2;
      marker_bit = pes_file_data_[offset] & 1;
      EXPECT_EQ(1, marker_bit);
      bytes_left -= 5;
      offset++;
    }

    // Validate stuffing byte(s).
    for (int i = 0; i < bytes_left; ++i)
      EXPECT_EQ(0xff, pes_file_data_[offset + i]);

    offset += bytes_left;
    EXPECT_EQ(kPesHeaderSize + kPesOptionalHeaderSize, offset);

    read_pos_ += kPesOptionalHeaderSize;
    parse_state_ = kParseBcmvHeader;
  }

  // Parses and validates a BCMV header.
  void ParseBcmvHeader(BcmvHeader* header) {
    ASSERT_TRUE(header != nullptr);
    EXPECT_EQ(kParseBcmvHeader, kParseBcmvHeader);
    std::size_t offset = read_pos_;
    header->id[0] = pes_file_data_[offset++];
    header->id[1] = pes_file_data_[offset++];
    header->id[2] = pes_file_data_[offset++];
    header->id[3] = pes_file_data_[offset++];

    header->length |= pes_file_data_[offset++] << 24;
    header->length |= pes_file_data_[offset++] << 16;
    header->length |= pes_file_data_[offset++] << 8;
    header->length |= pes_file_data_[offset++];

    // Length stored in the BCMV header is followed by 2 bytes of 0 padding.
    EXPECT_EQ(0, pes_file_data_[offset++]);
    EXPECT_EQ(0, pes_file_data_[offset++]);

    EXPECT_TRUE(header->Valid());

    // TODO(tomfinegan): Verify data instead of jumping to the next packet.
    read_pos_ += kBcmvHeaderSize + header->length;
    parse_state_ = kParsePesHeader;
  }

  ~Webm2PesTests() = default;

  const std::string& pes_file_name() const { return temp_file_name_.name(); }
  std::uint64_t pes_file_size() const { return pes_file_size_; }
  const PesFileData& pes_file_data() const { return pes_file_data_; }

 private:
  const libwebm::test::TempFileDeleter temp_file_name_;
  const std::string input_file_name_ =
      libwebm::test::GetTestFilePath("bbb_480p_vp9_opus_1second.webm");
  std::uint64_t pes_file_size_ = 0;
  PesFileData pes_file_data_;
  std::size_t read_pos_;
  ParseState parse_state_;
};

TEST_F(Webm2PesTests, CreatePesFile) {
  ASSERT_TRUE(CreateAndLoadTestInput());
}

TEST_F(Webm2PesTests, CanParseFirstPacket) {
  ASSERT_TRUE(CreateAndLoadTestInput());

  //
  // Parse the PES Header.
  // This is number of bytes following the final byte in the 6 byte static PES
  // header. PES optional header is 9 bytes. Payload is 83 bytes.
  PesHeader header;
  ParsePesHeader(&header);
  const std::size_t kPesOptionalHeaderLength = 9;
  const std::size_t kFirstFrameLength = 83;
  const std::size_t kPesPayloadLength =
      kPesOptionalHeaderLength + kFirstFrameLength;
  EXPECT_EQ(kPesPayloadLength, header.packet_length);

  //
  // Parse the PES optional header.
  //
  ParsePesOptionalHeader(&header.opt_header);

  EXPECT_EQ(kPesOptionalHeaderMarkerValue, header.opt_header.marker);
  EXPECT_EQ(0, header.opt_header.scrambling);
  EXPECT_EQ(0, header.opt_header.priority);
  EXPECT_EQ(0, header.opt_header.data_alignment);
  EXPECT_EQ(0, header.opt_header.copyright);
  EXPECT_EQ(0, header.opt_header.original);
  EXPECT_EQ(1, header.opt_header.has_pts);
  EXPECT_EQ(0, header.opt_header.has_dts);
  EXPECT_EQ(0, header.opt_header.unused_fields);

  //
  // Parse the BCMV Header
  //
  ParseBcmvHeader(&header.bcmv_header);
  EXPECT_EQ(kFirstFrameLength, header.bcmv_header.length);

  // Parse the next PES header to confirm correct parsing and consumption of
  // payload.
  ParsePesHeader(&header);
}

}  // namespace

int main(int argc, char* argv[]) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<commit_msg>webm2pes: Fix tests.<commit_after>// Copyright (c) 2016 The WebM project authors. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS.  All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
#include "webm2pes.h"

#include <cstdint>
#include <cstdio>
#include <limits>
#include <vector>

#include "gtest/gtest.h"

#include "common/libwebm_utils.h"
#include "testing/test_util.h"

namespace {

struct PesOptionalHeader {
  int marker = 0;
  int scrambling = 0;
  int priority = 0;
  int data_alignment = 0;
  int copyright = 0;
  int original = 0;
  int has_pts = 0;
  int has_dts = 0;
  int unused_fields = 0;
  int remaining_size = 0;
  int pts_dts_flag = 0;
  std::uint64_t pts = 0;
  int stuffing_byte = 0;
};

struct BcmvHeader {
  BcmvHeader() = default;
  ~BcmvHeader() = default;
  BcmvHeader(const BcmvHeader&) = delete;
  BcmvHeader(BcmvHeader&&) = delete;

  // Convenience ctor for quick validation of expected values via operator==
  // after parsing input.
  explicit BcmvHeader(std::uint32_t len) : length(len) {
    id[0] = 'B';
    id[1] = 'C';
    id[2] = 'M';
    id[3] = 'V';
  }

  bool operator==(const BcmvHeader& other) const {
    return (other.length == length && other.id[0] == id[0] &&
            other.id[1] == id[1] && other.id[2] == id[2] &&
            other.id[3] == id[3]);
  }

  bool Valid() const {
    return (length > 0 && length <= std::numeric_limits<std::uint16_t>::max() &&
            id[0] == 'B' && id[1] == 'C' && id[2] == 'M' && id[3] == 'V');
  }

  char id[4] = {0};
  std::uint32_t length = 0;
};

struct PesHeader {
  std::uint16_t packet_length = 0;
  PesOptionalHeader opt_header;
  BcmvHeader bcmv_header;
};

class Webm2PesTests : public ::testing::Test {
 public:
  typedef std::vector<std::uint8_t> PesFileData;

  enum ParseState {
    kParsePesHeader,
    kParsePesOptionalHeader,
    kParseBcmvHeader,
  };

  // Constants for validating known values from input data.
  const std::uint8_t kMinVideoStreamId = 0xE0;
  const std::uint8_t kMaxVideoStreamId = 0xEF;
  const std::size_t kPesHeaderSize = 6;
  const std::size_t kPesOptionalHeaderStartOffset = kPesHeaderSize;
  const std::size_t kPesOptionalHeaderSize = 9;
  const int kPesOptionalHeaderMarkerValue = 0x2;
  const std::size_t kWebm2PesOptHeaderRemainingSize = 6;
  const std::size_t kBcmvHeaderSize = 10;

  Webm2PesTests() : read_pos_(0), parse_state_(kParsePesHeader) {}

  void CreateAndLoadTestInput() {
    libwebm::Webm2Pes converter(input_file_name_, temp_file_name_.name());
    ASSERT_TRUE(converter.ConvertToFile());
    pes_file_size_ = libwebm::test::GetFileSize(pes_file_name());
    ASSERT_GT(pes_file_size_, 0);
    pes_file_data_.reserve(pes_file_size_);
    libwebm::FilePtr file = libwebm::FilePtr(
        std::fopen(pes_file_name().c_str(), "rb"), libwebm::FILEDeleter());

    int byte;
    while ((byte = fgetc(file.get())) != EOF)
      pes_file_data_.push_back(static_cast<std::uint8_t>(byte));

    ASSERT_TRUE(feof(file.get()) && !ferror(file.get()));
    ASSERT_EQ(pes_file_size_, pes_file_data_.size());
    read_pos_ = 0;
    parse_state_ = kParsePesHeader;
  }

  bool VerifyPacketStartCode() {
    EXPECT_LT(read_pos_ + 2, pes_file_data_.size());

    // PES packets all start with the byte sequence 0x0 0x0 0x1.
    if (pes_file_data_[read_pos_] != 0 || pes_file_data_[read_pos_ + 1] != 0 ||
        pes_file_data_[read_pos_ + 2] != 1) {
      return false;
    }
    return true;
  }

  std::uint8_t ReadStreamId() {
    EXPECT_LT(read_pos_ + 3, pes_file_data_.size());
    return pes_file_data_[read_pos_ + 3]; }

  std::uint16_t ReadPacketLength() {
    EXPECT_LT(read_pos_ + 5, pes_file_data_.size());

    // Read and byte swap 16 bit big endian length.
    return (pes_file_data_[read_pos_ + 4] << 8) | pes_file_data_[read_pos_ + 5];
  }

  void ParsePesHeader(PesHeader* header) {
    ASSERT_TRUE(header != nullptr);
    EXPECT_EQ(kParsePesHeader, parse_state_);
    EXPECT_TRUE(VerifyPacketStartCode());
    // PES Video stream IDs start at E0.
    EXPECT_GE(ReadStreamId(), kMinVideoStreamId);
    EXPECT_LE(ReadStreamId(), kMaxVideoStreamId);
    header->packet_length = ReadPacketLength();
    read_pos_ += kPesHeaderSize;
    parse_state_ = kParsePesOptionalHeader;
  }

  // Parses a PES optional header.
  // https://en.wikipedia.org/wiki/Packetized_elementary_stream
  // TODO(tomfinegan): Make these masks constants.
  void ParsePesOptionalHeader(PesOptionalHeader* header) {
    ASSERT_TRUE(header != nullptr);
    EXPECT_EQ(kParsePesOptionalHeader, parse_state_);
    std::size_t offset = read_pos_;
    EXPECT_LT(offset, pes_file_size_);

    header->marker = (pes_file_data_[offset] & 0x80) >> 6;
    header->scrambling = (pes_file_data_[offset] & 0x30) >> 4;
    header->priority = (pes_file_data_[offset] & 0x8) >> 3;
    header->data_alignment = (pes_file_data_[offset] & 0xc) >> 2;
    header->copyright = (pes_file_data_[offset] & 0x2) >> 1;
    header->original = pes_file_data_[offset] & 0x1;

    offset++;
    header->has_pts = (pes_file_data_[offset] & 0x80) >> 7;
    header->has_dts = (pes_file_data_[offset] & 0x40) >> 6;
    header->unused_fields = pes_file_data_[offset] & 0x3f;

    offset++;
    header->remaining_size = pes_file_data_[offset];
    EXPECT_EQ(kWebm2PesOptHeaderRemainingSize, header->remaining_size);

    int bytes_left = header->remaining_size;

    if (header->has_pts) {
      // Read PTS markers. Format:
      // PTS: 5 bytes
      //   4 bits (flag: PTS present, but no DTS): 0x2 ('0010')
      //   36 bits (90khz PTS):
      //     top 3 bits
      //     marker ('1')
      //     middle 15 bits
      //     marker ('1')
      //     bottom 15 bits
      //     marker ('1')
      // TODO(tomfinegan): Extract some golden timestamp values and actually
      // read the timestamp.
      offset++;
      header->pts_dts_flag = (pes_file_data_[offset] & 0x20) >> 4;
      // Check the marker bits.
      int marker_bit = pes_file_data_[offset] & 1;
      EXPECT_EQ(1, marker_bit);
      offset += 2;
      marker_bit = pes_file_data_[offset] & 1;
      EXPECT_EQ(1, marker_bit);
      offset += 2;
      marker_bit = pes_file_data_[offset] & 1;
      EXPECT_EQ(1, marker_bit);
      bytes_left -= 5;
      offset++;
    }

    // Validate stuffing byte(s).
    for (int i = 0; i < bytes_left; ++i)
      EXPECT_EQ(0xff, pes_file_data_[offset + i]);

    offset += bytes_left;
    EXPECT_EQ(kPesHeaderSize + kPesOptionalHeaderSize, offset);

    read_pos_ += kPesOptionalHeaderSize;
    parse_state_ = kParseBcmvHeader;
  }

  // Parses and validates a BCMV header.
  void ParseBcmvHeader(BcmvHeader* header) {
    ASSERT_TRUE(header != nullptr);
    EXPECT_EQ(kParseBcmvHeader, kParseBcmvHeader);
    std::size_t offset = read_pos_;
    header->id[0] = pes_file_data_[offset++];
    header->id[1] = pes_file_data_[offset++];
    header->id[2] = pes_file_data_[offset++];
    header->id[3] = pes_file_data_[offset++];

    header->length |= pes_file_data_[offset++] << 24;
    header->length |= pes_file_data_[offset++] << 16;
    header->length |= pes_file_data_[offset++] << 8;
    header->length |= pes_file_data_[offset++];

    // Length stored in the BCMV header is followed by 2 bytes of 0 padding.
    EXPECT_EQ(0, pes_file_data_[offset++]);
    EXPECT_EQ(0, pes_file_data_[offset++]);

    EXPECT_TRUE(header->Valid());

    // TODO(tomfinegan): Verify data instead of jumping to the next packet.
    read_pos_ += kBcmvHeaderSize + header->length;
    parse_state_ = kParsePesHeader;
  }

  ~Webm2PesTests() = default;

  const std::string& pes_file_name() const { return temp_file_name_.name(); }
  std::uint64_t pes_file_size() const { return pes_file_size_; }
  const PesFileData& pes_file_data() const { return pes_file_data_; }

 private:
  const libwebm::test::TempFileDeleter temp_file_name_;
  const std::string input_file_name_ =
      libwebm::test::GetTestFilePath("bbb_480p_vp9_opus_1second.webm");
  std::uint64_t pes_file_size_ = 0;
  PesFileData pes_file_data_;
  std::size_t read_pos_;
  ParseState parse_state_;
};

TEST_F(Webm2PesTests, CreatePesFile) { CreateAndLoadTestInput(); }

TEST_F(Webm2PesTests, CanParseFirstPacket) {
  CreateAndLoadTestInput();

  //
  // Parse the PES Header.
  // This is number of bytes following the final byte in the 6 byte static PES
  // header. PES optional header is 9 bytes. Payload is 83 bytes.
  PesHeader header;
  ParsePesHeader(&header);
  const std::size_t kPesOptionalHeaderLength = 9;
  const std::size_t kFirstFrameLength = 83;
  const std::size_t kPesPayloadLength =
      kPesOptionalHeaderLength + kFirstFrameLength;
  EXPECT_EQ(kPesPayloadLength, header.packet_length);

  //
  // Parse the PES optional header.
  //
  ParsePesOptionalHeader(&header.opt_header);

  EXPECT_EQ(kPesOptionalHeaderMarkerValue, header.opt_header.marker);
  EXPECT_EQ(0, header.opt_header.scrambling);
  EXPECT_EQ(0, header.opt_header.priority);
  EXPECT_EQ(0, header.opt_header.data_alignment);
  EXPECT_EQ(0, header.opt_header.copyright);
  EXPECT_EQ(0, header.opt_header.original);
  EXPECT_EQ(1, header.opt_header.has_pts);
  EXPECT_EQ(0, header.opt_header.has_dts);
  EXPECT_EQ(0, header.opt_header.unused_fields);

  //
  // Parse the BCMV Header
  //
  ParseBcmvHeader(&header.bcmv_header);
  EXPECT_EQ(kFirstFrameLength, header.bcmv_header.length);

  // Parse the next PES header to confirm correct parsing and consumption of
  // payload.
  ParsePesHeader(&header);
}

}  // namespace

int main(int argc, char* argv[]) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>/*
 * This file is part of the CN24 semantic segmentation software,
 * copyright (C) 2015 Clemens-Alexander Brust (ikosa dot de at gmail dot com).
 *
 * For licensing information, see the LICENSE file included with this project.
 */

#include <cn24.h>

#include <vector>
#include <utility>
#include <string>
#include <cmath>
#include <random>

// TEST SETUP
unsigned int RANDOM_RUNS = 15;
unsigned int SAMPLES = 2, WIDTH = 9, HEIGHT = 6, MAPS = 3;
Conv::datum epsilon = 0.005;

std::vector<std::pair<std::string, unsigned int>> test_layers_and_runs = {
  {"maxpooling(size=3x3)",1},
  {"maxpooling(size=3x2)",1},
  {"amaxpooling(size=3x3)",1},
  {"amaxpooling(size=3x2)",1},
  {"amaxpooling(size=3x3 stride=2x2)",1},
  {"convolution(size=3x3 kernels=3)",RANDOM_RUNS},
  {"convolution(size=3x3 stride=2x2 kernels=3)",RANDOM_RUNS},
  {"convolution(size=3x3 group=3 kernels=9)",RANDOM_RUNS},
  {"hmax(mu=0.1 weight=0.0)",1},
  // {"hmax(mu=0.1 weight=0.2)",1},
  {"tanh",1},{"sigm",1},{"relu",1},
  {"gradientaccumulation(outputs=2)",1},
  {"resize(border=2x2)",1}
};

// UTILITIES
Conv::datum SimpleSumLoss(Conv::Layer* layer, const Conv::Tensor& tensor) {
#ifdef BUILD_OPENCL
  ((Conv::Tensor&)tensor).MoveToCPU();
#endif
  Conv::datum sum = 0;

  for (unsigned int e = 0; e < tensor.elements(); e++) {
    const Conv::datum element = tensor.data_ptr_const()[e];
    sum += fabs(element);
  }

  return sum;
}

Conv::datum SimpleSumLoss(Conv::Layer* layer, const std::vector<Conv::CombinedTensor*>& outputs) {
  Conv::datum sum = 0;

  for (unsigned int o = 0; o < outputs.size(); o++) {
    sum += SimpleSumLoss(layer, outputs[o]->data);
  }

  Conv::LossFunctionLayer* loss_layer = dynamic_cast<Conv::LossFunctionLayer*>(layer);
  if (loss_layer != NULL)
    sum += loss_layer->CalculateLossFunction();

  return sum;
}

void SimpleSumLossGradient(const std::vector<Conv::CombinedTensor*>& outputs) {
  for (unsigned int o = 0; o < outputs.size(); o++) {
    Conv::Tensor& tensor = outputs[o]->data;
    Conv::Tensor& delta_tensor = outputs[o]->delta;
#ifdef BUILD_OPENCL
    tensor.MoveToCPU();
    delta_tensor.MoveToCPU();
#endif
    for (unsigned int e = 0; e < tensor.elements(); e++) {
      const Conv::datum element = tensor.data_ptr_const()[e];
      const Conv::datum gradient = element > 0.0 ? 1.0 : -1.0;
      delta_tensor.data_ptr()[e] = gradient;
    }
  }
}

int main(int argc, char* argv[]) {
  if((argc > 1 && std::string("-v").compare(argv[1]) == 0) || argc > 2) {
    Conv::System::Init(3);
  } else {
    Conv::System::Init();
  }

  std::mt19937 seed_generator(93023);
  std::uniform_real_distribution<Conv::datum> dist(1.0, 2.0);

  Conv::NetStatus net_status;
  net_status.SetIsTesting(true);

  bool test_failed = false;

  Conv::CombinedTensor input_data(SAMPLES, WIDTH, HEIGHT, MAPS);

  std::vector<std::string> test_layers;

  if (argc > 1) {
    std::string test_layer = argv[1];
    test_layers.push_back(test_layer);
  } else {
    for (std::pair<std::string, unsigned int>& layer_pair : test_layers_and_runs) {
      std::string& layer_descriptor = layer_pair.first;
      unsigned int runs = layer_pair.second;
      for(unsigned int i = 0; i < runs; i++) {
        // Inject random seeds
        std::string injected_descriptor = Conv::LayerFactory::InjectSeed(layer_descriptor, seed_generator());
        test_layers.push_back(injected_descriptor);
      }
    }
  }

  for (std::string& layer_descriptor : test_layers) {
    bool data_sign = seed_generator() % 2 == 0;
    for(unsigned int e = 0; e < input_data.data.elements(); e++) {
      if(data_sign)
        input_data.data.data_ptr()[e] = dist(seed_generator);
      else
        input_data.data.data_ptr()[e] = -dist(seed_generator);
    }
    input_data.delta.Clear(0.0);

    LOGINFO << "Testing layer: " << layer_descriptor;
    Conv::Layer* layer = Conv::LayerFactory::ConstructLayer(layer_descriptor);
    if(layer == nullptr) {
      test_failed = true;
      LOGINFO << "    Constructing...";
      LOGERROR << "        FAILED";
      continue;
    }

    LOGDEBUG << "    Description: " << layer->GetLayerDescription();
    LOGDEBUG << "    Configuration: " << layer->GetLayerConfiguration();

    if (Conv::LayerFactory::ExtractConfiguration(layer_descriptor).length() > 0
        && layer->GetLayerConfiguration().length() == 0) {
      test_failed = true;
      LOGINFO << "    Testing configuration loss...";
      LOGERROR << "       FAILED";
      continue;
    }

    std::vector<Conv::CombinedTensor*> outputs;
    bool createoutputs_success = layer->CreateOutputs({&input_data}, outputs);
    if(!createoutputs_success) {
      test_failed = true;
      LOGINFO << "    Creating outputs...";
      LOGERROR << "       FAILED";
      continue;
    }

    for(Conv::CombinedTensor* output : outputs) {
      LOGDEBUG << "        Output: " << output->data;
    }

    bool connect_success = layer->Connect({&input_data}, outputs, &net_status);
    if(!connect_success) {
      test_failed = true;
      LOGINFO << "    Connecting...";
      LOGERROR << "        FAILED";
      continue;
    }

    layer->OnLayerConnect({});

    if(layer->parameters().size() == 0) {
      LOGDEBUG << "    Layer has no weights";
    }

    // Function pointers for external gradient check
    void (*WriteLossDeltas)(const std::vector<Conv::CombinedTensor*>&) =
      SimpleSumLossGradient;
    Conv::datum (*CalculateLoss)(Conv::Layer*, const std::vector<Conv::CombinedTensor*>&) =
      SimpleSumLoss;

    for(Conv::CombinedTensor* weights : layer->parameters()) {
      bool gradient_success = Conv::GradientTester::DoGradientTest(layer, weights->data, weights->delta, outputs, epsilon, WriteLossDeltas, CalculateLoss);
      if(!gradient_success) {
        test_failed = true;
        LOGINFO << "    Gradient test (weights)...";
        LOGERROR << "        FAILED";
        continue;
      }
    }

    bool gradient_success = Conv::GradientTester::DoGradientTest(layer, input_data.data, input_data.delta, outputs, epsilon, WriteLossDeltas, CalculateLoss);
    if(!gradient_success) {
      test_failed = true;
      LOGINFO << "    Gradient test (inputs)...";
      LOGERROR << "        FAILED";
      continue;
    }

    delete layer;
    for(Conv::CombinedTensor* output : outputs)
      delete output;
  }

  Conv::System::Shutdown();

  return test_failed ? -1 : 0;
}
<commit_msg>SimpleLayerTest: Reintroduced HMax with non-zero weights<commit_after>/*
 * This file is part of the CN24 semantic segmentation software,
 * copyright (C) 2015 Clemens-Alexander Brust (ikosa dot de at gmail dot com).
 *
 * For licensing information, see the LICENSE file included with this project.
 */

#include <cn24.h>

#include <vector>
#include <utility>
#include <string>
#include <cmath>
#include <random>

// TEST SETUP
unsigned int RANDOM_RUNS = 15;
unsigned int SAMPLES = 2, WIDTH = 9, HEIGHT = 6, MAPS = 3;
Conv::datum epsilon = 0.005;

std::vector<std::pair<std::string, unsigned int>> test_layers_and_runs = {
  {"maxpooling(size=3x3)",1},
  {"maxpooling(size=3x2)",1},
  {"amaxpooling(size=3x3)",1},
  {"amaxpooling(size=3x2)",1},
  {"amaxpooling(size=3x3 stride=2x2)",1},
  {"convolution(size=3x3 kernels=3)",RANDOM_RUNS},
  {"convolution(size=3x3 stride=2x2 kernels=3)",RANDOM_RUNS},
  {"convolution(size=3x3 group=3 kernels=9)",RANDOM_RUNS},
  {"hmax(mu=0.1 weight=0.0)",1},
  {"hmax(mu=0.1 weight=0.2)",1},
  {"tanh",1},{"sigm",1},{"relu",1},
  {"gradientaccumulation(outputs=2)",1},
  {"resize(border=2x2)",1}
};

// UTILITIES
Conv::datum SimpleSumLoss(Conv::Layer* layer, const Conv::Tensor& tensor) {
#ifdef BUILD_OPENCL
  ((Conv::Tensor&)tensor).MoveToCPU();
#endif
  Conv::datum sum = 0;

  for (unsigned int e = 0; e < tensor.elements(); e++) {
    const Conv::datum element = tensor.data_ptr_const()[e];
    sum += fabs(element);
  }

  return sum;
}

Conv::datum SimpleSumLoss(Conv::Layer* layer, const std::vector<Conv::CombinedTensor*>& outputs) {
  Conv::datum sum = 0;

  for (unsigned int o = 0; o < outputs.size(); o++) {
    sum += SimpleSumLoss(layer, outputs[o]->data);
  }

  Conv::LossFunctionLayer* loss_layer = dynamic_cast<Conv::LossFunctionLayer*>(layer);
  if (loss_layer != NULL)
    sum += loss_layer->CalculateLossFunction();

  return sum;
}

void SimpleSumLossGradient(const std::vector<Conv::CombinedTensor*>& outputs) {
  for (unsigned int o = 0; o < outputs.size(); o++) {
    Conv::Tensor& tensor = outputs[o]->data;
    Conv::Tensor& delta_tensor = outputs[o]->delta;
#ifdef BUILD_OPENCL
    tensor.MoveToCPU();
    delta_tensor.MoveToCPU();
#endif
    for (unsigned int e = 0; e < tensor.elements(); e++) {
      const Conv::datum element = tensor.data_ptr_const()[e];
      const Conv::datum gradient = element > 0.0 ? 1.0 : -1.0;
      delta_tensor.data_ptr()[e] = gradient;
    }
  }
}

int main(int argc, char* argv[]) {
  if((argc > 1 && std::string("-v").compare(argv[1]) == 0) || argc > 2) {
    Conv::System::Init(3);
  } else {
    Conv::System::Init();
  }

  std::mt19937 seed_generator(93023);
  std::uniform_real_distribution<Conv::datum> dist(1.0, 2.0);

  Conv::NetStatus net_status;
  net_status.SetIsTesting(true);

  bool test_failed = false;

  Conv::CombinedTensor input_data(SAMPLES, WIDTH, HEIGHT, MAPS);

  std::vector<std::string> test_layers;

  if (argc > 1) {
    std::string test_layer = argv[1];
    test_layers.push_back(test_layer);
  } else {
    for (std::pair<std::string, unsigned int>& layer_pair : test_layers_and_runs) {
      std::string& layer_descriptor = layer_pair.first;
      unsigned int runs = layer_pair.second;
      for(unsigned int i = 0; i < runs; i++) {
        // Inject random seeds
        std::string injected_descriptor = Conv::LayerFactory::InjectSeed(layer_descriptor, seed_generator());
        test_layers.push_back(injected_descriptor);
      }
    }
  }

  for (std::string& layer_descriptor : test_layers) {
    bool data_sign = seed_generator() % 2 == 0;
    for(unsigned int e = 0; e < input_data.data.elements(); e++) {
      if(data_sign)
        input_data.data.data_ptr()[e] = dist(seed_generator);
      else
        input_data.data.data_ptr()[e] = -dist(seed_generator);
    }
    input_data.delta.Clear(0.0);

    LOGINFO << "Testing layer: " << layer_descriptor;
    Conv::Layer* layer = Conv::LayerFactory::ConstructLayer(layer_descriptor);
    if(layer == nullptr) {
      test_failed = true;
      LOGINFO << "    Constructing...";
      LOGERROR << "        FAILED";
      continue;
    }

    LOGDEBUG << "    Description: " << layer->GetLayerDescription();
    LOGDEBUG << "    Configuration: " << layer->GetLayerConfiguration();

    if (Conv::LayerFactory::ExtractConfiguration(layer_descriptor).length() > 0
        && layer->GetLayerConfiguration().length() == 0) {
      test_failed = true;
      LOGINFO << "    Testing configuration loss...";
      LOGERROR << "       FAILED";
      continue;
    }

    std::vector<Conv::CombinedTensor*> outputs;
    bool createoutputs_success = layer->CreateOutputs({&input_data}, outputs);
    if(!createoutputs_success) {
      test_failed = true;
      LOGINFO << "    Creating outputs...";
      LOGERROR << "       FAILED";
      continue;
    }

    for(Conv::CombinedTensor* output : outputs) {
      LOGDEBUG << "        Output: " << output->data;
    }

    bool connect_success = layer->Connect({&input_data}, outputs, &net_status);
    if(!connect_success) {
      test_failed = true;
      LOGINFO << "    Connecting...";
      LOGERROR << "        FAILED";
      continue;
    }

    layer->OnLayerConnect({});

    if(layer->parameters().size() == 0) {
      LOGDEBUG << "    Layer has no weights";
    }

    // Function pointers for external gradient check
    void (*WriteLossDeltas)(const std::vector<Conv::CombinedTensor*>&) =
      SimpleSumLossGradient;
    Conv::datum (*CalculateLoss)(Conv::Layer*, const std::vector<Conv::CombinedTensor*>&) =
      SimpleSumLoss;

    for(Conv::CombinedTensor* weights : layer->parameters()) {
      bool gradient_success = Conv::GradientTester::DoGradientTest(layer, weights->data, weights->delta, outputs, epsilon, WriteLossDeltas, CalculateLoss);
      if(!gradient_success) {
        test_failed = true;
        LOGINFO << "    Gradient test (weights)...";
        LOGERROR << "        FAILED";
        continue;
      }
    }

    bool gradient_success = Conv::GradientTester::DoGradientTest(layer, input_data.data, input_data.delta, outputs, epsilon, WriteLossDeltas, CalculateLoss);
    if(!gradient_success) {
      test_failed = true;
      LOGINFO << "    Gradient test (inputs)...";
      LOGERROR << "        FAILED";
      continue;
    }

    delete layer;
    for(Conv::CombinedTensor* output : outputs)
      delete output;
  }

  Conv::System::Shutdown();

  return test_failed ? -1 : 0;
}
<|endoftext|>


<commit_before>// Ignore unused parameter warnings coming from cppunit headers
#include <libmesh/ignore_warnings.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/TestCase.h>
#include <libmesh/restore_warnings.h>

#include <libmesh/equation_systems.h>
#include <libmesh/mesh.h>
#include <libmesh/mesh_generation.h>
#include <libmesh/elem.h>
#include <libmesh/dof_map.h>

#include "test_comm.h"

// THE CPPUNIT_TEST_SUITE_END macro expands to code that involves
// std::auto_ptr, which in turn produces -Wdeprecated-declarations
// warnings.  These can be ignored in GCC as long as we wrap the
// offending code in appropriate pragmas.  We can't get away with a
// single ignore_warnings.h inclusion at the beginning of this file,
// since the libmesh headers pull in a restore_warnings.h at some
// point.  We also don't bother restoring warnings at the end of this
// file since it's not a header.
#include <libmesh/ignore_warnings.h>

using namespace libMesh;

// This class is used by testCyclicConstraintDetection
class MyConstraint : public System::Constraint
{
private:

  System & _sys;

public:

  MyConstraint( System & sys ) : Constraint(), _sys(sys) {}

  virtual ~MyConstraint() {}

  void constrain()
  {
    {
      const dof_id_type constrained_dof_index = 0;
      DofConstraintRow constraint_row;
      constraint_row[1] = 1.0;
      _sys.get_dof_map().add_constraint_row( constrained_dof_index, constraint_row, 0., true);
    }
    {
      const dof_id_type constrained_dof_index = 1;
      DofConstraintRow constraint_row;
      constraint_row[0] = 1.0;
      _sys.get_dof_map().add_constraint_row( constrained_dof_index, constraint_row, 0., true);
    }
  }
};

class DofMapTest : public CppUnit::TestCase {
public:
  CPPUNIT_TEST_SUITE( DofMapTest );

  CPPUNIT_TEST( testDofOwnerOnEdge3 );
  CPPUNIT_TEST( testDofOwnerOnQuad9 );
  CPPUNIT_TEST( testDofOwnerOnTri6 );
  CPPUNIT_TEST( testDofOwnerOnHex27 );

#ifdef LIBMESH_ENABLE_CONSTRAINTS
  CPPUNIT_TEST( testCyclicConstraintDetection );
#endif // LIBMESH_ENABLE_CONSTRAINTS

  CPPUNIT_TEST_SUITE_END();

private:

public:
  void setUp()
  {}

  void tearDown()
  {}

  void testDofOwner(const ElemType elem_type)
  {
    Mesh mesh(*TestCommWorld);

    EquationSystems es(mesh);
    System &sys = es.add_system<System> ("SimpleSystem");
    sys.add_variable("u", THIRD, HIERARCHIC);

    const unsigned n_elem_per_side = 3;
    const std::unique_ptr<Elem> test_elem = Elem::build(elem_type);
    const Real ymax = test_elem->dim() > 1;
    const Real zmax = test_elem->dim() > 2;
    const unsigned int ny = ymax * n_elem_per_side;
    const unsigned int nz = zmax * n_elem_per_side;

    MeshTools::Generation::build_cube (mesh,
                                       n_elem_per_side,
                                       ny,
                                       nz,
                                       0., 1.,
                                       0., ymax,
                                       0., zmax,
                                       elem_type);

    es.init();

    DofMap & dof_map = sys.get_dof_map();
    for (dof_id_type id = 0; id != dof_map.n_dofs(); ++id)
      {
        const processor_id_type pid = dof_map.dof_owner(id);
        CPPUNIT_ASSERT(dof_map.first_dof(pid) <= id);
        CPPUNIT_ASSERT(id < dof_map.end_dof(pid));
      }
  }

  void testDofOwnerOnEdge3() { testDofOwner(EDGE3); }
  void testDofOwnerOnQuad9() { testDofOwner(QUAD9); }
  void testDofOwnerOnTri6()  { testDofOwner(TRI6); }
  void testDofOwnerOnHex27() { testDofOwner(HEX27); }

#ifdef LIBMESH_ENABLE_CONSTRAINTS
  void testCyclicConstraintDetection()
  {
    Mesh mesh(*TestCommWorld);

    EquationSystems es(mesh);
    System & sys = es.add_system<System> ("SimpleSystem");
    sys.add_variable("u", FIRST);

    MyConstraint my_constraint(sys);
    sys.attach_constraint_object(my_constraint);

    MeshTools::Generation::build_square (mesh,4,4,-1., 1.,-1., 1., QUAD4);

    // Tell the dof_map to check for cyclic constraints
    DofMap & dof_map = sys.get_dof_map();
    dof_map.set_error_on_cyclic_constraint(true);

    CPPUNIT_ASSERT_THROW_MESSAGE("Cyclic constraint not detected", es.init(), libMesh::LogicError);
  }
#endif // LIBMESH_ENABLE_CONSTRAINTS

};

CPPUNIT_TEST_SUITE_REGISTRATION( DofMapTest );
<commit_msg>DofMapTest: testCyclicConstraintDetection() requires exceptions.<commit_after>// Ignore unused parameter warnings coming from cppunit headers
#include <libmesh/ignore_warnings.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/TestCase.h>
#include <libmesh/restore_warnings.h>

#include <libmesh/equation_systems.h>
#include <libmesh/mesh.h>
#include <libmesh/mesh_generation.h>
#include <libmesh/elem.h>
#include <libmesh/dof_map.h>

#include "test_comm.h"

// THE CPPUNIT_TEST_SUITE_END macro expands to code that involves
// std::auto_ptr, which in turn produces -Wdeprecated-declarations
// warnings.  These can be ignored in GCC as long as we wrap the
// offending code in appropriate pragmas.  We can't get away with a
// single ignore_warnings.h inclusion at the beginning of this file,
// since the libmesh headers pull in a restore_warnings.h at some
// point.  We also don't bother restoring warnings at the end of this
// file since it's not a header.
#include <libmesh/ignore_warnings.h>

using namespace libMesh;

// This class is used by testCyclicConstraintDetection
class MyConstraint : public System::Constraint
{
private:

  System & _sys;

public:

  MyConstraint( System & sys ) : Constraint(), _sys(sys) {}

  virtual ~MyConstraint() {}

  void constrain()
  {
    {
      const dof_id_type constrained_dof_index = 0;
      DofConstraintRow constraint_row;
      constraint_row[1] = 1.0;
      _sys.get_dof_map().add_constraint_row( constrained_dof_index, constraint_row, 0., true);
    }
    {
      const dof_id_type constrained_dof_index = 1;
      DofConstraintRow constraint_row;
      constraint_row[0] = 1.0;
      _sys.get_dof_map().add_constraint_row( constrained_dof_index, constraint_row, 0., true);
    }
  }
};

class DofMapTest : public CppUnit::TestCase {
public:
  CPPUNIT_TEST_SUITE( DofMapTest );

  CPPUNIT_TEST( testDofOwnerOnEdge3 );
  CPPUNIT_TEST( testDofOwnerOnQuad9 );
  CPPUNIT_TEST( testDofOwnerOnTri6 );
  CPPUNIT_TEST( testDofOwnerOnHex27 );

#if defined(LIBMESH_ENABLE_CONSTRAINTS) && defined(LIBMESH_ENABLE_EXCEPTIONS)
  CPPUNIT_TEST( testCyclicConstraintDetection );
#endif

  CPPUNIT_TEST_SUITE_END();

private:

public:
  void setUp()
  {}

  void tearDown()
  {}

  void testDofOwner(const ElemType elem_type)
  {
    Mesh mesh(*TestCommWorld);

    EquationSystems es(mesh);
    System &sys = es.add_system<System> ("SimpleSystem");
    sys.add_variable("u", THIRD, HIERARCHIC);

    const unsigned n_elem_per_side = 3;
    const std::unique_ptr<Elem> test_elem = Elem::build(elem_type);
    const Real ymax = test_elem->dim() > 1;
    const Real zmax = test_elem->dim() > 2;
    const unsigned int ny = ymax * n_elem_per_side;
    const unsigned int nz = zmax * n_elem_per_side;

    MeshTools::Generation::build_cube (mesh,
                                       n_elem_per_side,
                                       ny,
                                       nz,
                                       0., 1.,
                                       0., ymax,
                                       0., zmax,
                                       elem_type);

    es.init();

    DofMap & dof_map = sys.get_dof_map();
    for (dof_id_type id = 0; id != dof_map.n_dofs(); ++id)
      {
        const processor_id_type pid = dof_map.dof_owner(id);
        CPPUNIT_ASSERT(dof_map.first_dof(pid) <= id);
        CPPUNIT_ASSERT(id < dof_map.end_dof(pid));
      }
  }

  void testDofOwnerOnEdge3() { testDofOwner(EDGE3); }
  void testDofOwnerOnQuad9() { testDofOwner(QUAD9); }
  void testDofOwnerOnTri6()  { testDofOwner(TRI6); }
  void testDofOwnerOnHex27() { testDofOwner(HEX27); }

#if defined(LIBMESH_ENABLE_CONSTRAINTS) && defined(LIBMESH_ENABLE_EXCEPTIONS)
  void testCyclicConstraintDetection()
  {
    Mesh mesh(*TestCommWorld);

    EquationSystems es(mesh);
    System & sys = es.add_system<System> ("SimpleSystem");
    sys.add_variable("u", FIRST);

    MyConstraint my_constraint(sys);
    sys.attach_constraint_object(my_constraint);

    MeshTools::Generation::build_square (mesh,4,4,-1., 1.,-1., 1., QUAD4);

    // Tell the dof_map to check for cyclic constraints
    DofMap & dof_map = sys.get_dof_map();
    dof_map.set_error_on_cyclic_constraint(true);

    CPPUNIT_ASSERT_THROW_MESSAGE("Cyclic constraint not detected", es.init(), libMesh::LogicError);
  }
#endif

};

CPPUNIT_TEST_SUITE_REGISTRATION( DofMapTest );
<|endoftext|>


<commit_before>/*  This file is part of the KDE project
    Copyright (C) 2007 Matthias Kretz <kretz@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

*/

#include "../mediasource.h"
#include "../abstractmediastream.h"
#include "loadfakebackend.h"

#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QUrl>
#include <qtest_kde.h>
#include <QtCore/QObject>

class MediaSourceTest : public QObject
{
    Q_OBJECT
    private Q_SLOTS:
        void initTestCase();
        void testLocalFile();
        void testUrl();
        void testDiscType();
        void testStream();
        void testIODevice();
        void testQtResource();
        void cleanupTestCase();
};

using namespace Phonon;

void MediaSourceTest::initTestCase()
{
    // no need for a backend at all
    // Phonon::loadFakeBackend();
}

void MediaSourceTest::testLocalFile()
{
    QString filename("/usr/share/sounds/KDE_Beep.ogg");
    AbstractMediaStream *stream = 0;

    MediaSource a(filename);
    QCOMPARE(a.type(), MediaSource::LocalFile);
    QCOMPARE(a.fileName(), filename);
    QCOMPARE(a.url(), QUrl::fromLocalFile(filename));
    QCOMPARE(a.discType(), Phonon::NoDisc);
    QCOMPARE(a.stream(), stream);
    QCOMPARE(a.deviceName(), QString());
    //QCOMPARE(a.audioCaptureDevice(), AudioCaptureDevice());
    //QCOMPARE(a.videoCaptureDevice(), VideoCaptureDevice());
    MediaSource b(a);
    MediaSource c;
    c = a;
    QCOMPARE(a, b);
    QCOMPARE(a, c);
    QCOMPARE(b, c);

    QCOMPARE(b.type(), MediaSource::LocalFile);
    QCOMPARE(b.fileName(), filename);
    QCOMPARE(b.url(), QUrl::fromLocalFile(filename));
    QCOMPARE(b.discType(), Phonon::NoDisc);
    QCOMPARE(b.stream(), stream);
    QCOMPARE(b.deviceName(), QString());
    //QCOMPARE(b.audioCaptureDevice(), AudioCaptureDevice());
    //QCOMPARE(b.videoCaptureDevice(), VideoCaptureDevice());

    QCOMPARE(c.type(), MediaSource::LocalFile);
    QCOMPARE(c.fileName(), filename);
    QCOMPARE(c.url(), QUrl::fromLocalFile(filename));
    QCOMPARE(c.discType(), Phonon::NoDisc);
    QCOMPARE(c.stream(), stream);
    QCOMPARE(c.deviceName(), QString());
    //QCOMPARE(c.audioCaptureDevice(), AudioCaptureDevice());
    //QCOMPARE(c.videoCaptureDevice(), VideoCaptureDevice());

    //test that a relative file path is correctly set as an absolute URL
    filename = "foo.ogg";
    MediaSource relative(filename);
    //QCOMPARE(relative.fileName(), filename);
    QFileInfo urlInfo(relative.url().toLocalFile());
    QVERIFY(urlInfo.isAbsolute());
    QCOMPARE(urlInfo.fileName(), filename);
    QCOMPARE(urlInfo.absolutePath(), QDir::currentPath());
}

void MediaSourceTest::testUrl()
{
    QUrl url("http://www.example.com/music.ogg");
    AbstractMediaStream *stream = 0;

    MediaSource a(url);
    QCOMPARE(a.type(), MediaSource::Url);
    QCOMPARE(a.fileName(), QString());
    QCOMPARE(a.url(), url);
    QCOMPARE(a.discType(), Phonon::NoDisc);
    QCOMPARE(a.stream(), stream);
    QCOMPARE(a.deviceName(), QString());
    //QCOMPARE(a.audioCaptureDevice(), AudioCaptureDevice());
    //QCOMPARE(a.videoCaptureDevice(), VideoCaptureDevice());
    MediaSource b(a);
    MediaSource c;
    c = a;
    QCOMPARE(a, b);
    QCOMPARE(a, c);
    QCOMPARE(b, c);

    QCOMPARE(b.type(), MediaSource::Url);
    QCOMPARE(b.fileName(), QString());
    QCOMPARE(b.url(), url);
    QCOMPARE(b.discType(), Phonon::NoDisc);
    QCOMPARE(b.stream(), stream);
    QCOMPARE(b.deviceName(), QString());
    //QCOMPARE(b.audioCaptureDevice(), AudioCaptureDevice());
    //QCOMPARE(b.videoCaptureDevice(), VideoCaptureDevice());

    QCOMPARE(c.type(), MediaSource::Url);
    QCOMPARE(c.fileName(), QString());
    QCOMPARE(c.url(), url);
    QCOMPARE(c.discType(), Phonon::NoDisc);
    QCOMPARE(c.stream(), stream);
    QCOMPARE(c.deviceName(), QString());
    //QCOMPARE(c.audioCaptureDevice(), AudioCaptureDevice());
    //QCOMPARE(c.videoCaptureDevice(), VideoCaptureDevice());
}

void MediaSourceTest::testDiscType()
{
    for (int i = 0; i <= Phonon::Vcd; ++i) {
        Phonon::DiscType discType = static_cast<Phonon::DiscType>(i);
        AbstractMediaStream *stream = 0;

        MediaSource a(discType);

        QCOMPARE(a.type(), MediaSource::Disc);
        QCOMPARE(a.fileName(), QString());
        QCOMPARE(a.url(), QUrl());
        QCOMPARE(a.discType(), discType);
        QCOMPARE(a.stream(), stream);
        QCOMPARE(a.deviceName(), QString());
        //QCOMPARE(a.audioCaptureDevice(), AudioCaptureDevice());
        //QCOMPARE(a.videoCaptureDevice(), VideoCaptureDevice());
        MediaSource b(a);
        MediaSource c;
        c = a;
        QCOMPARE(a, b);
        QCOMPARE(a, c);
        QCOMPARE(b, c);

        QCOMPARE(b.type(), MediaSource::Disc);
        QCOMPARE(b.fileName(), QString());
        QCOMPARE(b.url(), QUrl());
        QCOMPARE(b.discType(), discType);
        QCOMPARE(b.stream(), stream);
        QCOMPARE(b.deviceName(), QString());
        //QCOMPARE(b.audioCaptureDevice(), AudioCaptureDevice());
        //QCOMPARE(b.videoCaptureDevice(), VideoCaptureDevice());

        QCOMPARE(c.type(), MediaSource::Disc);
        QCOMPARE(c.fileName(), QString());
        QCOMPARE(c.url(), QUrl());
        QCOMPARE(c.discType(), discType);
        QCOMPARE(c.stream(), stream);
        QCOMPARE(c.deviceName(), QString());
        //QCOMPARE(c.audioCaptureDevice(), AudioCaptureDevice());
        //QCOMPARE(c.videoCaptureDevice(), VideoCaptureDevice());
    }
}

class Stream : public AbstractMediaStream
{
    public:
        void reset() {}
        void needData() {}
        void enoughData() {}
};

void MediaSourceTest::testStream()
{
    AbstractMediaStream *stream = new Stream;

    MediaSource a(stream);
    QCOMPARE(a.type(), MediaSource::Stream);
    QCOMPARE(a.fileName(), QString());
    QCOMPARE(a.url(), QUrl());
    QCOMPARE(a.discType(), Phonon::NoDisc);
    QCOMPARE(a.stream(), stream);
    QCOMPARE(a.deviceName(), QString());
    //QCOMPARE(a.audioCaptureDevice(), AudioCaptureDevice());
    //QCOMPARE(a.videoCaptureDevice(), VideoCaptureDevice());
    MediaSource b(a);
    MediaSource c;
    c = a;
    QCOMPARE(a, b);
    QCOMPARE(a, c);
    QCOMPARE(b, c);

    QCOMPARE(b.type(), MediaSource::Stream);
    QCOMPARE(b.fileName(), QString());
    QCOMPARE(b.url(), QUrl());
    QCOMPARE(b.discType(), Phonon::NoDisc);
    QCOMPARE(b.stream(), stream);
    QCOMPARE(b.deviceName(), QString());
    //QCOMPARE(b.audioCaptureDevice(), AudioCaptureDevice());
    //QCOMPARE(b.videoCaptureDevice(), VideoCaptureDevice());

    QCOMPARE(c.type(), MediaSource::Stream);
    QCOMPARE(c.fileName(), QString());
    QCOMPARE(c.url(), QUrl());
    QCOMPARE(c.discType(), Phonon::NoDisc);
    QCOMPARE(c.stream(), stream);
    QCOMPARE(c.deviceName(), QString());
    //QCOMPARE(c.audioCaptureDevice(), AudioCaptureDevice());
    //QCOMPARE(c.videoCaptureDevice(), VideoCaptureDevice());

    delete stream;
    QCOMPARE(a.type(), MediaSource::Invalid);
    QCOMPARE(b.type(), MediaSource::Invalid);
    QCOMPARE(c.type(), MediaSource::Invalid);
    const AbstractMediaStream *null = 0;
    QCOMPARE(a.stream(), null);
    QCOMPARE(b.stream(), null);
    QCOMPARE(c.stream(), null);
}

void MediaSourceTest::testIODevice()
{
    const QByteArray data("0192380");
    QBuffer *buffer = new QBuffer;
    buffer->setData(data);
    buffer->open(QIODevice::ReadOnly);

    MediaSource a(buffer);
    QCOMPARE(a.type(), MediaSource::Stream);
    QCOMPARE(a.fileName(), QString());
    QCOMPARE(a.url(), QUrl());
    QCOMPARE(a.discType(), Phonon::NoDisc);
    QVERIFY(a.stream() != 0);
    QCOMPARE(a.deviceName(), QString());
    //QCOMPARE(a.audioCaptureDevice(), AudioCaptureDevice());
    //QCOMPARE(a.videoCaptureDevice(), VideoCaptureDevice());
    MediaSource b(a);
    MediaSource c;
    c = a;
    QCOMPARE(a, b);
    QCOMPARE(a, c);
    QCOMPARE(b, c);

    QCOMPARE(b.type(), MediaSource::Stream);
    QCOMPARE(b.fileName(), QString());
    QCOMPARE(b.url(), QUrl());
    QCOMPARE(b.discType(), Phonon::NoDisc);
    QVERIFY(b.stream() != 0);
    QCOMPARE(b.deviceName(), QString());
    //QCOMPARE(b.audioCaptureDevice(), AudioCaptureDevice());
    //QCOMPARE(b.videoCaptureDevice(), VideoCaptureDevice());

    QCOMPARE(c.type(), MediaSource::Stream);
    QCOMPARE(c.fileName(), QString());
    QCOMPARE(c.url(), QUrl());
    QCOMPARE(c.discType(), Phonon::NoDisc);
    QVERIFY(c.stream() != 0);
    QCOMPARE(c.deviceName(), QString());
    //QCOMPARE(c.audioCaptureDevice(), AudioCaptureDevice());
    //QCOMPARE(c.videoCaptureDevice(), VideoCaptureDevice());

    delete buffer;
    QCOMPARE(a.type(), MediaSource::Invalid);
    QCOMPARE(b.type(), MediaSource::Invalid);
    QCOMPARE(c.type(), MediaSource::Invalid);
    const AbstractMediaStream *null = 0;
    QCOMPARE(a.stream(), null);
    QCOMPARE(b.stream(), null);
    QCOMPARE(c.stream(), null);
}

void MediaSourceTest::testQtResource()
{
    const QString filename(":/ogg/zero.ogg");
    MediaSource a(filename);
    QCOMPARE(a.type(), MediaSource::Stream);
    QCOMPARE(a.fileName(), QString());
    QCOMPARE(a.url(), QUrl());
    QCOMPARE(a.discType(), Phonon::NoDisc);
    QVERIFY(a.stream() != 0);
    QCOMPARE(a.deviceName(), QString());
    //QCOMPARE(a.audioCaptureDevice(), AudioCaptureDevice());
    //QCOMPARE(a.videoCaptureDevice(), VideoCaptureDevice());
    MediaSource b(a);
    MediaSource c;
    c = a;
    QCOMPARE(a, b);
    QCOMPARE(a, c);
    QCOMPARE(b, c);

    QCOMPARE(b.type(), MediaSource::Stream);
    QCOMPARE(b.fileName(), QString());
    QCOMPARE(b.url(), QUrl());
    QCOMPARE(b.discType(), Phonon::NoDisc);
    QVERIFY(b.stream() != 0);
    QCOMPARE(b.deviceName(), QString());
    //QCOMPARE(b.audioCaptureDevice(), AudioCaptureDevice());
    //QCOMPARE(b.videoCaptureDevice(), VideoCaptureDevice());

    QCOMPARE(c.type(), MediaSource::Stream);
    QCOMPARE(c.fileName(), QString());
    QCOMPARE(c.url(), QUrl());
    QCOMPARE(c.discType(), Phonon::NoDisc);
    QVERIFY(c.stream() != 0);
    QCOMPARE(c.deviceName(), QString());
    //QCOMPARE(c.audioCaptureDevice(), AudioCaptureDevice());
    //QCOMPARE(c.videoCaptureDevice(), VideoCaptureDevice());
}

void MediaSourceTest::cleanupTestCase()
{
}

QTEST_APPLESS_MAIN(MediaSourceTest)

#include "mediasourcetest.moc"
// vim: sw=4 sts=4 et tw=100
<commit_msg>fix tests<commit_after>/*  This file is part of the KDE project
    Copyright (C) 2007 Matthias Kretz <kretz@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

*/

#include "../mediasource.h"
#include "../abstractmediastream.h"
#include "loadfakebackend.h"

#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QUrl>
#include <qtest_kde.h>
#include <QtCore/QObject>

class MediaSourceTest : public QObject
{
    Q_OBJECT
    private Q_SLOTS:
        void initTestCase();
        void testLocalFile();
        void testUrl();
        void testDiscType();
        void testStream();
        void testIODevice();
        void testQtResource();
        void cleanupTestCase();
};

using namespace Phonon;

void MediaSourceTest::initTestCase()
{
    // no need for a backend at all
    // Phonon::loadFakeBackend();
}

void MediaSourceTest::testLocalFile()
{
    QString filename("/usr/share/sounds/KDE_Beep.ogg");
    AbstractMediaStream *stream = 0;

    MediaSource a(filename);
    QCOMPARE(a.type(), MediaSource::LocalFile);
    QCOMPARE(a.fileName(), filename);
    QCOMPARE(a.url(), QUrl::fromLocalFile(filename));
    QCOMPARE(a.discType(), Phonon::NoDisc);
    QCOMPARE(a.stream(), stream);
    QCOMPARE(a.deviceName(), QString());
    //QCOMPARE(a.audioCaptureDevice(), AudioCaptureDevice());
    //QCOMPARE(a.videoCaptureDevice(), VideoCaptureDevice());
    MediaSource b(a);
    MediaSource c;
    c = a;
    QCOMPARE(a, b);
    QCOMPARE(a, c);
    QCOMPARE(b, c);

    QCOMPARE(b.type(), MediaSource::LocalFile);
    QCOMPARE(b.fileName(), filename);
    QCOMPARE(b.url(), QUrl::fromLocalFile(filename));
    QCOMPARE(b.discType(), Phonon::NoDisc);
    QCOMPARE(b.stream(), stream);
    QCOMPARE(b.deviceName(), QString());
    //QCOMPARE(b.audioCaptureDevice(), AudioCaptureDevice());
    //QCOMPARE(b.videoCaptureDevice(), VideoCaptureDevice());

    QCOMPARE(c.type(), MediaSource::LocalFile);
    QCOMPARE(c.fileName(), filename);
    QCOMPARE(c.url(), QUrl::fromLocalFile(filename));
    QCOMPARE(c.discType(), Phonon::NoDisc);
    QCOMPARE(c.stream(), stream);
    QCOMPARE(c.deviceName(), QString());
    //QCOMPARE(c.audioCaptureDevice(), AudioCaptureDevice());
    //QCOMPARE(c.videoCaptureDevice(), VideoCaptureDevice());

    // non-existing files should become invalid sources
    filename = "/some/invalid/file.xyz";
    MediaSource invalid(filename);
    QCOMPARE(invalid.type(), MediaSource::Invalid);
    QCOMPARE(invalid.fileName(), QString());

    //test that a relative file path is correctly set as an absolute URL
    QFile testFile("foo.ogg");
    bool deleteFile = false;
    if (!testFile.exists()) {
        deleteFile = true;
        testFile.open(QIODevice::WriteOnly);
        testFile.close();
    }
    filename = "foo.ogg";
    MediaSource relative(filename);
    //QCOMPARE(relative.fileName(), filename);
    QFileInfo urlInfo(relative.url().toLocalFile());
    QVERIFY(urlInfo.isAbsolute());
    QCOMPARE(urlInfo.fileName(), filename);
    QCOMPARE(urlInfo.absolutePath(), QDir::currentPath());
    if (deleteFile) {
        testFile.remove();
    }
}

void MediaSourceTest::testUrl()
{
    QUrl url("http://www.example.com/music.ogg");
    AbstractMediaStream *stream = 0;

    MediaSource a(url);
    QCOMPARE(a.type(), MediaSource::Url);
    QCOMPARE(a.fileName(), QString());
    QCOMPARE(a.url(), url);
    QCOMPARE(a.discType(), Phonon::NoDisc);
    QCOMPARE(a.stream(), stream);
    QCOMPARE(a.deviceName(), QString());
    //QCOMPARE(a.audioCaptureDevice(), AudioCaptureDevice());
    //QCOMPARE(a.videoCaptureDevice(), VideoCaptureDevice());
    MediaSource b(a);
    MediaSource c;
    c = a;
    QCOMPARE(a, b);
    QCOMPARE(a, c);
    QCOMPARE(b, c);

    QCOMPARE(b.type(), MediaSource::Url);
    QCOMPARE(b.fileName(), QString());
    QCOMPARE(b.url(), url);
    QCOMPARE(b.discType(), Phonon::NoDisc);
    QCOMPARE(b.stream(), stream);
    QCOMPARE(b.deviceName(), QString());
    //QCOMPARE(b.audioCaptureDevice(), AudioCaptureDevice());
    //QCOMPARE(b.videoCaptureDevice(), VideoCaptureDevice());

    QCOMPARE(c.type(), MediaSource::Url);
    QCOMPARE(c.fileName(), QString());
    QCOMPARE(c.url(), url);
    QCOMPARE(c.discType(), Phonon::NoDisc);
    QCOMPARE(c.stream(), stream);
    QCOMPARE(c.deviceName(), QString());
    //QCOMPARE(c.audioCaptureDevice(), AudioCaptureDevice());
    //QCOMPARE(c.videoCaptureDevice(), VideoCaptureDevice());
}

void MediaSourceTest::testDiscType()
{
    for (int i = 0; i <= Phonon::Vcd; ++i) {
        Phonon::DiscType discType = static_cast<Phonon::DiscType>(i);
        AbstractMediaStream *stream = 0;

        MediaSource a(discType);

        QCOMPARE(a.type(), MediaSource::Disc);
        QCOMPARE(a.fileName(), QString());
        QCOMPARE(a.url(), QUrl());
        QCOMPARE(a.discType(), discType);
        QCOMPARE(a.stream(), stream);
        QCOMPARE(a.deviceName(), QString());
        //QCOMPARE(a.audioCaptureDevice(), AudioCaptureDevice());
        //QCOMPARE(a.videoCaptureDevice(), VideoCaptureDevice());
        MediaSource b(a);
        MediaSource c;
        c = a;
        QCOMPARE(a, b);
        QCOMPARE(a, c);
        QCOMPARE(b, c);

        QCOMPARE(b.type(), MediaSource::Disc);
        QCOMPARE(b.fileName(), QString());
        QCOMPARE(b.url(), QUrl());
        QCOMPARE(b.discType(), discType);
        QCOMPARE(b.stream(), stream);
        QCOMPARE(b.deviceName(), QString());
        //QCOMPARE(b.audioCaptureDevice(), AudioCaptureDevice());
        //QCOMPARE(b.videoCaptureDevice(), VideoCaptureDevice());

        QCOMPARE(c.type(), MediaSource::Disc);
        QCOMPARE(c.fileName(), QString());
        QCOMPARE(c.url(), QUrl());
        QCOMPARE(c.discType(), discType);
        QCOMPARE(c.stream(), stream);
        QCOMPARE(c.deviceName(), QString());
        //QCOMPARE(c.audioCaptureDevice(), AudioCaptureDevice());
        //QCOMPARE(c.videoCaptureDevice(), VideoCaptureDevice());
    }
}

class Stream : public AbstractMediaStream
{
    public:
        void reset() {}
        void needData() {}
        void enoughData() {}
};

void MediaSourceTest::testStream()
{
    AbstractMediaStream *stream = new Stream;

    MediaSource a(stream);
    QCOMPARE(a.type(), MediaSource::Stream);
    QCOMPARE(a.fileName(), QString());
    QCOMPARE(a.url(), QUrl());
    QCOMPARE(a.discType(), Phonon::NoDisc);
    QCOMPARE(a.stream(), stream);
    QCOMPARE(a.deviceName(), QString());
    //QCOMPARE(a.audioCaptureDevice(), AudioCaptureDevice());
    //QCOMPARE(a.videoCaptureDevice(), VideoCaptureDevice());
    MediaSource b(a);
    MediaSource c;
    c = a;
    QCOMPARE(a, b);
    QCOMPARE(a, c);
    QCOMPARE(b, c);

    QCOMPARE(b.type(), MediaSource::Stream);
    QCOMPARE(b.fileName(), QString());
    QCOMPARE(b.url(), QUrl());
    QCOMPARE(b.discType(), Phonon::NoDisc);
    QCOMPARE(b.stream(), stream);
    QCOMPARE(b.deviceName(), QString());
    //QCOMPARE(b.audioCaptureDevice(), AudioCaptureDevice());
    //QCOMPARE(b.videoCaptureDevice(), VideoCaptureDevice());

    QCOMPARE(c.type(), MediaSource::Stream);
    QCOMPARE(c.fileName(), QString());
    QCOMPARE(c.url(), QUrl());
    QCOMPARE(c.discType(), Phonon::NoDisc);
    QCOMPARE(c.stream(), stream);
    QCOMPARE(c.deviceName(), QString());
    //QCOMPARE(c.audioCaptureDevice(), AudioCaptureDevice());
    //QCOMPARE(c.videoCaptureDevice(), VideoCaptureDevice());

    delete stream;
    QCOMPARE(a.type(), MediaSource::Invalid);
    QCOMPARE(b.type(), MediaSource::Invalid);
    QCOMPARE(c.type(), MediaSource::Invalid);
    const AbstractMediaStream *null = 0;
    QCOMPARE(a.stream(), null);
    QCOMPARE(b.stream(), null);
    QCOMPARE(c.stream(), null);
}

void MediaSourceTest::testIODevice()
{
    const QByteArray data("0192380");
    QBuffer *buffer = new QBuffer;
    buffer->setData(data);
    buffer->open(QIODevice::ReadOnly);

    MediaSource a(buffer);
    QCOMPARE(a.type(), MediaSource::Stream);
    QCOMPARE(a.fileName(), QString());
    QCOMPARE(a.url(), QUrl());
    QCOMPARE(a.discType(), Phonon::NoDisc);
    QVERIFY(a.stream() != 0);
    QCOMPARE(a.deviceName(), QString());
    //QCOMPARE(a.audioCaptureDevice(), AudioCaptureDevice());
    //QCOMPARE(a.videoCaptureDevice(), VideoCaptureDevice());
    MediaSource b(a);
    MediaSource c;
    c = a;
    QCOMPARE(a, b);
    QCOMPARE(a, c);
    QCOMPARE(b, c);

    QCOMPARE(b.type(), MediaSource::Stream);
    QCOMPARE(b.fileName(), QString());
    QCOMPARE(b.url(), QUrl());
    QCOMPARE(b.discType(), Phonon::NoDisc);
    QVERIFY(b.stream() != 0);
    QCOMPARE(b.deviceName(), QString());
    //QCOMPARE(b.audioCaptureDevice(), AudioCaptureDevice());
    //QCOMPARE(b.videoCaptureDevice(), VideoCaptureDevice());

    QCOMPARE(c.type(), MediaSource::Stream);
    QCOMPARE(c.fileName(), QString());
    QCOMPARE(c.url(), QUrl());
    QCOMPARE(c.discType(), Phonon::NoDisc);
    QVERIFY(c.stream() != 0);
    QCOMPARE(c.deviceName(), QString());
    //QCOMPARE(c.audioCaptureDevice(), AudioCaptureDevice());
    //QCOMPARE(c.videoCaptureDevice(), VideoCaptureDevice());

    delete buffer;
    QCOMPARE(a.type(), MediaSource::Invalid);
    QCOMPARE(b.type(), MediaSource::Invalid);
    QCOMPARE(c.type(), MediaSource::Invalid);
    const AbstractMediaStream *null = 0;
    QCOMPARE(a.stream(), null);
    QCOMPARE(b.stream(), null);
    QCOMPARE(c.stream(), null);
}

void MediaSourceTest::testQtResource()
{
    const QString filename(":/ogg/zero.ogg");
    MediaSource a(filename);
    QCOMPARE(a.type(), MediaSource::Stream);
    QCOMPARE(a.fileName(), QString());
    QCOMPARE(a.url(), QUrl());
    QCOMPARE(a.discType(), Phonon::NoDisc);
    QVERIFY(a.stream() != 0);
    QCOMPARE(a.deviceName(), QString());
    //QCOMPARE(a.audioCaptureDevice(), AudioCaptureDevice());
    //QCOMPARE(a.videoCaptureDevice(), VideoCaptureDevice());
    MediaSource b(a);
    MediaSource c;
    c = a;
    QCOMPARE(a, b);
    QCOMPARE(a, c);
    QCOMPARE(b, c);

    QCOMPARE(b.type(), MediaSource::Stream);
    QCOMPARE(b.fileName(), QString());
    QCOMPARE(b.url(), QUrl());
    QCOMPARE(b.discType(), Phonon::NoDisc);
    QVERIFY(b.stream() != 0);
    QCOMPARE(b.deviceName(), QString());
    //QCOMPARE(b.audioCaptureDevice(), AudioCaptureDevice());
    //QCOMPARE(b.videoCaptureDevice(), VideoCaptureDevice());

    QCOMPARE(c.type(), MediaSource::Stream);
    QCOMPARE(c.fileName(), QString());
    QCOMPARE(c.url(), QUrl());
    QCOMPARE(c.discType(), Phonon::NoDisc);
    QVERIFY(c.stream() != 0);
    QCOMPARE(c.deviceName(), QString());
    //QCOMPARE(c.audioCaptureDevice(), AudioCaptureDevice());
    //QCOMPARE(c.videoCaptureDevice(), VideoCaptureDevice());
}

void MediaSourceTest::cleanupTestCase()
{
}

QTEST_APPLESS_MAIN(MediaSourceTest)

#include "mediasourcetest.moc"
// vim: sw=4 sts=4 et tw=100
<|endoftext|>


<commit_before>/*
   Mathieu Stefani, 07 février 2016

   Example of a REST endpoint with routing
*/

#include "gtest/gtest.h"

#include <pistache/http.h>
#include <pistache/router.h>
#include <pistache/endpoint.h>

#include "httplib.h"

using namespace std;
using namespace Pistache;

class StatsEndpoint {
public:
    StatsEndpoint(Address addr)
        : httpEndpoint(std::make_shared<Http::Endpoint>(addr))
    { }

    void init(size_t thr = 2) {
        auto opts = Http::Endpoint::options()
                .threads(thr)
                .flags(Tcp::Options::InstallSignalHandler);
        httpEndpoint->init(opts);
        setupRoutes();
    }

    void start() {
        httpEndpoint->setHandler(router.handler());
        httpEndpoint->serveThreaded();
    }

    void shutdown() {
        httpEndpoint->shutdown();
    }

private:
    void setupRoutes() {
        using namespace Rest;
        Routes::Get(router, "/read/function1", Routes::bind(&StatsEndpoint::doAuth, this));
    }

    void doAuth(const Rest::Request& /*request*/, Http::ResponseWriter response) {
        std::thread worker([](Http::ResponseWriter writer) {
            writer.send(Http::Code::Ok, "1");
        }, std::move(response));
        worker.detach();
    }

    std::shared_ptr<Http::Endpoint> httpEndpoint;
    Rest::Router router;
};

TEST(rest_server_test, basic_test) {
    Port port(9090);
    int thr = 1;

    Address addr(Ipv4::any(), port);

    StatsEndpoint stats(addr);

    stats.init(thr);
    stats.start();

    cout << "Cores = " << hardware_concurrency() << endl;
    cout << "Using " << thr << " threads" << endl;

    httplib::Client client("localhost", 9090);
    auto res = client.Get("/read/function1");
    ASSERT_EQ(res->status, 200);
    ASSERT_EQ(res->body, "1");

    stats.shutdown();
}
<commit_msg>Use emphemeral port for unit test.<commit_after>/*
   Mathieu Stefani, 07 février 2016

   Example of a REST endpoint with routing
*/

#include "gtest/gtest.h"

#include <pistache/http.h>
#include <pistache/router.h>
#include <pistache/endpoint.h>

#include "httplib.h"

using namespace std;
using namespace Pistache;

class StatsEndpoint {
public:
    StatsEndpoint(Address addr)
        : httpEndpoint(std::make_shared<Http::Endpoint>(addr))
    { }

    void init(size_t thr = 2) {
        auto opts = Http::Endpoint::options()
                .threads(thr)
                .flags(Tcp::Options::InstallSignalHandler);
        httpEndpoint->init(opts);
        setupRoutes();
    }

    void start() {
        httpEndpoint->setHandler(router.handler());
        httpEndpoint->serveThreaded();
    }

    void shutdown() {
        httpEndpoint->shutdown();
    }

    Port getPort() const {
        return httpEndpoint->getPort();
    }

private:
    void setupRoutes() {
        using namespace Rest;
        Routes::Get(router, "/read/function1", Routes::bind(&StatsEndpoint::doAuth, this));
    }

    void doAuth(const Rest::Request& /*request*/, Http::ResponseWriter response) {
        std::thread worker([](Http::ResponseWriter writer) {
            writer.send(Http::Code::Ok, "1");
        }, std::move(response));
        worker.detach();
    }

    std::shared_ptr<Http::Endpoint> httpEndpoint;
    Rest::Router router;
};

TEST(rest_server_test, basic_test) {
    int thr = 1;

    Address addr(Ipv4::any(), Port(0));

    StatsEndpoint stats(addr);

    stats.init(thr);
    stats.start();
    Port port = stats.getPort();

    cout << "Cores = " << hardware_concurrency() << endl;
    cout << "Using " << thr << " threads" << endl;
    cout << "Port = " << port << endl;

    httplib::Client client("localhost", port);
    auto res = client.Get("/read/function1");
    ASSERT_EQ(res->status, 200);
    ASSERT_EQ(res->body, "1");

    stats.shutdown();
}
<|endoftext|>


<commit_before>/*
    Copyright 2011 Joe Hermaszewski. All rights reserved.

    Redistribution and use in source and binary forms, with or without modification, are
    permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice, this list of
    conditions and the following disclaimer.

    2. 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.

    THIS SOFTWARE IS PROVIDED BY Joe Hermaszewski "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 Joe Hermaszewski 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 views and conclusions contained in the software and documentation are those of the
    authors and should not be interpreted as representing official policies, either expressed
    or implied, of Joe Hermaszewski.
*/

#include <iostream>
#include <joemath/joemath.hpp>
#include "timer.hpp"

using namespace NJoeMath;

const u32 NUM_ITERATIONS = 10000000;

void TestRandom()
{
    NTimer::CTimer timer;

    std::cout << "Random U32, ";

    NJoeMath::CRandom random;
    random.Seed( 6 );

    u32 acc = 0;

    timer.Start();

    for(u32 i = 0; i < NUM_ITERATIONS; ++i)
        acc += random.U32();

    timer.Stop();

    std::cout << double(NUM_ITERATIONS) / timer.GetElapsedTime() << ", " << acc << "\n";

}

float4 AddVec(float4& a, float4& b)
{
    return operator +<float, 1,4,float, float> (a,b);
}

int main( int argc, char** argv )
{
    TestRandom();

    NJoeMath::CRandom random;
    NTimer::CTimer time;
    time.Start();
    random.Seed((u32)(time.GetElapsedTime()*0xffffffff));

    float4 a(1.0f, 0.0f, 0.0f, 0.0f);
    float4 b(1.0f, 0.0f, 0.0f, 0.0f);

    CMatrix<float,1,2> c;
    CMatrix<float,1,2> d;
    operator /<float, 1,2,float, float, true> (c,d);

    float j = a[0];

    j = j/j;

    float3x3 r(1.0f, 0.0f, 0.0f,
               0.0f, 1.0f, 0.0f,
               0.0f, 0.0f, 1.0f);

    float fDet = r.Determinant();

    CMatrix<u32,4,4> q(1,0,0,0,
                       0,1,0,0,
                       0,0,1,0,
                       0,0,0,1);

    u32 uDet = q.Determinant();

    CMatrix<double,6,6> dd(0.0, 1.0, 0.0, 0.0, 0.0, 0.0,
                           2.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                           0.0, 0.0, 1.0, 0.0, 0.0, 0.0,
                           0.0, 0.0, 0.0, 1.0, 0.0, 0.0,
                           0.0, 0.0, 0.0, 0.0, 1.0, 0.0,
                           0.0, 0.0, 0.0, 0.0, 0.0, 1.0);

    double dDet = dd.Determinant();

    float3 y = r[2];

    a = AddVec(a,b);

    bool myBool = is_matrix<int>::value;

    myBool = is_matrix<CMatrix<float, 1,2>>::value;

    CMatrix<u32,2,2> mat( 1, 0,
                          0, 1 );

    u32 det = mat.Determinant();

    return det - det;

    return 0;
}

<commit_msg>[+] matrix inversion tests in speed test<commit_after>/*
    Copyright 2011 Joe Hermaszewski. All rights reserved.

    Redistribution and use in source and binary forms, with or without modification, are
    permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice, this list of
    conditions and the following disclaimer.

    2. 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.

    THIS SOFTWARE IS PROVIDED BY Joe Hermaszewski "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 Joe Hermaszewski 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 views and conclusions contained in the software and documentation are those of the
    authors and should not be interpreted as representing official policies, either expressed
    or implied, of Joe Hermaszewski.
*/

#include <iostream>
#include <joemath/joemath.hpp>
#include "timer.hpp"

using namespace NJoeMath;

const u32 NUM_ITERATIONS = 10000000;

void TestRandom()
{
    NTimer::CTimer timer;

    std::cout << "Random U32, ";

    NJoeMath::CRandom random;
    random.Seed( 6 );

    u32 acc = 0;

    timer.Start();

    for(u32 i = 0; i < NUM_ITERATIONS; ++i)
        acc += random.U32();

    timer.Stop();

    std::cout << double(NUM_ITERATIONS) / timer.GetElapsedTime() << ", " << acc << "\n";

}

float4 AddVec(float4& a, float4& b)
{
    return operator +<float, 1,4,float, float> (a,b);
}

int main( int argc, char** argv )
{
    TestRandom();

    NJoeMath::CRandom random;
    NTimer::CTimer time;
    time.Start();
    random.Seed((u32)(time.GetElapsedTime()*0xffffffff));

    float4 a(1.0f, 0.0f, 0.0f, 0.0f);
    float4 b(1.0f, 0.0f, 0.0f, 0.0f);

    CMatrix<float,1,2> c;
    CMatrix<float,1,2> d;
    operator /<float, 1,2,float, float, true> (c,d);

    float j = a[0];

    j = j/j;

    float3x3 r(0.0f, 2.0f, 2.0f,
               3.0f, 3.0f, 0.0f,
               1.0f, 0.0f, 1.0f);

    float ttt = r.Determinant();

    r.Invert();

    float fDet = r.Determinant();

    CMatrix<float,4,4> q(0.0f,1.0f,0.0f,0.0f,
                       2.0f,0.0f,0.0f,0.0f,
                       0.0f,0.0f,1.0f,0.0f,
                       0.0f,0.0f,0.0f,1.0f);

    q.Invert( );

    u32 uDet = q.Determinant();

    CMatrix<double,6,6> dd(0.0, 1.0, 0.0, 0.0, 0.0, 0.0,
                           2.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                           0.0, 0.0, 1.0, 0.0, 0.0, 0.0,
                           0.0, 0.0, 0.0, 1.0, 0.0, 0.0,
                           0.0, 0.0, 0.0, 0.0, 1.0, 0.0,
                           0.0, 0.0, 0.0, 0.0, 0.0, 1.0);

    double dDet = dd.Determinant();

    dd.Invert();

    float3 y = r[2];

    a = AddVec(a,b);

    bool myBool = is_matrix<int>::value;

    myBool = is_matrix<CMatrix<float, 1,2>>::value;

    CMatrix<u32,2,2> mat( 1, 0,
                          0, 1 );

    u32 det = mat.Determinant();

    mat.Transpose();

    mat.Invert();

    CMatrix<float,1,1> s(1.0f);
    s.Invert();

    float4 v0(1.0f, 1.0f, 1.0f, 1.0f);
    float4 v1(1.0f, 1.0f, 1.0f, 1.0f);

    u32 d0 = Dot(v0, v1);

    return det - det;

    return 0;
}

<|endoftext|>


<commit_before>/* -*- mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
 * Copyright (C) 2013  Pascal Giorgi
 *
 * Written by Pascal Giorgi <pascal.giorgi@lirmm.fr>
 *
 * ========LICENCE========
 * This file is part of the library LinBox.
 *
 * LinBox is free software: you can redistribute it and/or modify
 * it under the terms of the  GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * ========LICENCE========
 */

#ifdef HAVE_OPENMP
#include <omp.h>
#define GIVARO_USES_OMP
#include <givaro/givtimer.h>
#define gettime realtime
typedef Givaro::OMPTimer myTimer;
#else
#include <givaro/givtimer.h>
#define gettime usertime
typedef Givaro::Timer myTimer;
#endif

#include <functional>
#include <iostream>
#include <vector>
using namespace std;
#include <linbox/ring/modular.h>
#include <linbox/randiter/random-prime.h>
#include <linbox/randiter/random-fftprime.h>
//#include <linbox/field/unparametric.h>
#include <givaro/zring.h>
#include <recint/rint.h>
#include <linbox/matrix/matrix-domain.h>
#include <linbox/util/commentator.h>
#include <linbox/util/timer.h>
#include <linbox/matrix/polynomial-matrix.h>
#include <linbox/algorithms/polynomial-matrix/polynomial-matrix-domain.h>

using namespace LinBox;

template <typename Rand, typename Vect>
void randomVect (Rand& r, Vect& v) {
	size_t s = v.size();
	for (size_t i = 0; i < s; ++i)
		r.random(v[i]);
}

template <typename Rand, typename Mat>
void randomMat (Rand& r, Mat& m) {
	for (size_t i = 0; i < m.rowdim(); ++i)
		for (size_t j = 0; j < m.coldim(); ++j)
			r.random(m.refEntry(i,j));
}

template<typename Field, typename Rand>
void randomMatPol(Rand& r,  PolynomialMatrix<PMType::matfirst,PMStorage::plain,Field>& A){
	for(size_t i=0;i<A.size();i++)
		randomMat(r, A[i]);
}

template<typename Field, typename Rand>
void randomMatPol(Rand& r,  PolynomialMatrix<PMType::polfirst,PMStorage::plain,Field>& A){
	for(size_t i=0;i<A.rowdim()*A.coldim();i++)
		randomVect(r, A(i));
}

template<typename MatPol>
bool operator==(const MatPol& A, const MatPol& B){
	MatrixDomain<typename MatPol::Field> MD(A.field());
	if (A.size()!=B.size()|| A.rowdim()!= B.rowdim() || A.coldim()!=B.coldim())
		return false;
	size_t i=0;
	while (i<A.size() && MD.areEqual(A[i],B[i]))
		i++;

	if (i<A.size() && A.rowdim()<10 && A.coldim()<10){
		cout<<"first:"<<endl<<A<<endl;
		cout<<"second:"<<endl<<B<<endl;
	}

	return i==A.size();
}

template<typename MatrixP, typename Field, typename RandIter>
bool check_matpol_mul(const Field& fld,  RandIter& Gen, size_t n, size_t d) {
	MatrixP A(fld,n,n,d),B(fld,n,n,d),C(fld,n,n,2*d-1);

	// Generate random matrix of polynomial
	randomMatPol(Gen,A);
	randomMatPol(Gen,B);
	typedef PolynomialMatrixDomain<Field>    PolMatDom;
	PolMatDom  PMD(fld);
	PMD.mul(C,A,B);
	return check_mul(C,A,B,C.size());
}

template<typename MatrixP, typename Field, typename RandIter>
bool check_matpol_midp(const Field& fld,  RandIter& Gen, size_t n, size_t d) {
	MatrixP A(fld,n,n,d),C(fld,n,n,2*d-1);
	MatrixP B(fld,n,n,d);
	// Generate random matrix of polynomial
	randomMatPol(Gen,A);
	randomMatPol(Gen,C);
	typedef PolynomialMatrixDomain<Field>    PolMatDom;
	PolMatDom  PMD(fld);
	PMD.midproduct(B,A,C) ;
	return check_midproduct(B,A,C);
}

template<typename MatrixP, typename Field, typename RandIter>
bool check_matpol_midpgen(const Field& fld,  RandIter& Gen, size_t n, size_t d) {
	size_t d0,d1; // n0 must be in [d, 2d-1[

	d1=d/2;
	d0=d-d1;

	MatrixP A(fld,n,n,d0+1),B(fld,n,n,d1),C(fld,n,n,d);

	// Generate random matrix of polynomial
	randomMatPol(Gen,A);
	randomMatPol(Gen,C);
	typedef PolynomialMatrixDomain<Field>    PolMatDom;
	PolMatDom  PMD(fld);
	PMD.midproductgen(B,A,C,true,d0+1,d) ;
	return check_midproduct(B,A,C,true,d0+1,d);
}

template<typename Field>
bool launchTest(const Field& F, size_t n, long b, long d, long seed){
	bool ok=true;
	typename Field::RandIter G(F,b,seed);
	typedef PolynomialMatrix<PMType::polfirst,PMStorage::plain,Field> MatrixP;
	std::cerr<<"Polynomial matrix (polfirst) testing over ";F.write(std::cerr)<<std::endl;
	ok&=check_matpol_mul<MatrixP> (F,G,n,d);
	ok&=check_matpol_midp<MatrixP> (F,G,n,d);
	ok&=check_matpol_midpgen<MatrixP> (F,G,n,d);

	//typedef PolynomialMatrix<PMType::matfirst,PMStorage::plain,Field> PMatrix;
	// std::cerr<<"Polynomial matrix (matfirst) testing:\n";F.write(std::cerr)<<std::endl;
	// check_matpol_mul<PMatrix> (F,G,n,d);
	// check_matpol_midp<PMatrix> (F,G,n,d);
	return ok;
}

bool runTest(uint64_t n, uint64_t d, long seed){

	bool ok=true;
	// fourier prime < 2^(53--log(n))/2
	{
		size_t bits= (53-integer(n).bitsize())/2;
		RandomFFTPrime Rd(1<<bits,seed);
		integer p = Rd.randomPrime(integer(d).bitsize()+1);

		Givaro::Modular<double> F((int32_t)p);
		ok&=launchTest (F,n,bits,d,seed);

	}

	// normal prime < 2^(53--log(n))/2
	{
		size_t bits= (53-integer(n).bitsize())/2;;
		RandomPrimeIter Rd(bits,seed);
		integer p;
		Rd.random(p);

		Givaro::Modular<double> F((int32_t)p);
		ok&=launchTest (F,n,bits,d,seed);
	}

	// multi-precision prime
	{
		size_t bits=114;
		RandomPrimeIter Rd(bits,seed);
		integer p= Rd.random();

		Givaro::Modular<integer> F1(p);
		ok&=launchTest (F1,n,bits,d,seed);
		Givaro::Modular<RecInt::ruint128,RecInt::ruint256> F2(p);
		ok&=launchTest (F2,n,bits,d,seed);

	}
	// over the integer
	{
		Givaro::ZRing<integer> F;
		ok&=launchTest (F,n,128,d,seed);

	}
	return ok;
}

int main(int argc, char** argv){
	static size_t  n = 16; // matrix dimension
	static size_t  d = 512; // polynomial size
	static long    seed = time(NULL);

	static Argument args[] = {
		{ 'n', "-n N", "Set dimension of test matrices to NxN.", TYPE_INT,     &n },
		{ 'd', "-d D", "Set degree of test matrices to D.", TYPE_INT,     &d },
		{ 's', "-s s", "Set the random seed to a specific value", TYPE_INT, &seed},
		END_OF_ARGUMENTS
	};
	parseArguments (argc, argv, args);

	return (runTest(n,d,seed)? 0: -1);
}

<commit_msg>debugging<commit_after>/* -*- mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
 * Copyright (C) 2013  Pascal Giorgi
 *
 * Written by Pascal Giorgi <pascal.giorgi@lirmm.fr>
 *
 * ========LICENCE========
 * This file is part of the library LinBox.
 *
 * LinBox is free software: you can redistribute it and/or modify
 * it under the terms of the  GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * ========LICENCE========
 */

#ifdef HAVE_OPENMP
#include <omp.h>
#define GIVARO_USES_OMP
#include <givaro/givtimer.h>
#define gettime realtime
typedef Givaro::OMPTimer myTimer;
#else
#include <givaro/givtimer.h>
#define gettime usertime
typedef Givaro::Timer myTimer;
#endif

#include <functional>
#include <iostream>
#include <vector>
using namespace std;
#include <linbox/ring/modular.h>
#include <linbox/randiter/random-prime.h>
#include <linbox/randiter/random-fftprime.h>
//#include <linbox/field/unparametric.h>
#include <givaro/zring.h>
#include <recint/rint.h>
#include <linbox/matrix/matrix-domain.h>
#include <linbox/util/commentator.h>
#include <linbox/util/timer.h>
#include <linbox/matrix/polynomial-matrix.h>
#include <linbox/algorithms/polynomial-matrix/polynomial-matrix-domain.h>

using namespace LinBox;

template <typename Rand, typename Vect>
void randomVect (Rand& r, Vect& v) {
	size_t s = v.size();
	for (size_t i = 0; i < s; ++i)
		r.random(v[i]);
}

template <typename Rand, typename Mat>
void randomMat (Rand& r, Mat& m) {
	for (size_t i = 0; i < m.rowdim(); ++i)
		for (size_t j = 0; j < m.coldim(); ++j)
			r.random(m.refEntry(i,j));
}

template<typename Field, typename Rand>
void randomMatPol(Rand& r,  PolynomialMatrix<PMType::matfirst,PMStorage::plain,Field>& A){
	for(size_t i=0;i<A.size();i++)
		randomMat(r, A[i]);
}

template<typename Field, typename Rand>
void randomMatPol(Rand& r,  PolynomialMatrix<PMType::polfirst,PMStorage::plain,Field>& A){
	for(size_t i=0;i<A.rowdim()*A.coldim();i++)
		randomVect(r, A(i));
}

template<typename MatPol>
bool operator==(const MatPol& A, const MatPol& B){
	MatrixDomain<typename MatPol::Field> MD(A.field());
	if (A.size()!=B.size()|| A.rowdim()!= B.rowdim() || A.coldim()!=B.coldim())
		return false;
	size_t i=0;
	while (i<A.size() && MD.areEqual(A[i],B[i]))
		i++;

	if (i<A.size() && A.rowdim()<10 && A.coldim()<10){
		cout<<"first:"<<endl<<A<<endl;
		cout<<"second:"<<endl<<B<<endl;
	}

	return i==A.size();
}

template<typename MatrixP, typename Field, typename RandIter>
bool check_matpol_mul(const Field& fld,  RandIter& Gen, size_t n, size_t d) {
	MatrixP A(fld,n,n,d),B(fld,n,n,d),C(fld,n,n,2*d-1);

	// Generate random matrix of polynomial
	randomMatPol(Gen,A);
	randomMatPol(Gen,B);
	typedef PolynomialMatrixDomain<Field>    PolMatDom;
	PolMatDom  PMD(fld);
	PMD.mul(C,A,B);
	return check_mul(C,A,B,C.size());
}

template<typename MatrixP, typename Field, typename RandIter>
bool check_matpol_midp(const Field& fld,  RandIter& Gen, size_t n, size_t d) {
	MatrixP A(fld,n,n,d),C(fld,n,n,2*d-1);
	MatrixP B(fld,n,n,d);
	// Generate random matrix of polynomial
	randomMatPol(Gen,A);
	randomMatPol(Gen,C);
	typedef PolynomialMatrixDomain<Field>    PolMatDom;
	PolMatDom  PMD(fld);
	PMD.midproduct(B,A,C) ;
	return check_midproduct(B,A,C);
}

template<typename MatrixP, typename Field, typename RandIter>
bool check_matpol_midpgen(const Field& fld,  RandIter& Gen, size_t n, size_t d) {
	size_t d0,d1; // n0 must be in [d, 2d-1[

	d1=d/2;
	d0=d-d1;

	MatrixP A(fld,n,n,d0+1),B(fld,n,n,d1),C(fld,n,n,d);

	// Generate random matrix of polynomial
	randomMatPol(Gen,A);
	randomMatPol(Gen,C);
	typedef PolynomialMatrixDomain<Field>    PolMatDom;
	PolMatDom  PMD(fld);
	PMD.midproductgen(B,A,C,true,d0+1,d) ;
	return check_midproduct(B,A,C,true,d0+1,d);
}

template<typename MatrixP, typename Field, typename RandIter>
bool debug_midpgen_dlp(const Field& fld,  RandIter& Gen) {
	size_t d0,d1;
	size_t n0,n1;

	n0=84463;
	n1=168923;

	MatrixP A(fld,48,48,59061),B(fld,48,32,84461),C(fld,48,32,168923);

	// Generate random matrix of polynomial
	randomMatPol(Gen,A);
	randomMatPol(Gen,C);
	typedef PolynomialMatrixDomain<Field>    PolMatDom;
	PolMatDom  PMD(fld);
	PMD.midproductgen(B,A,C,true,n0,n1) ;
	return check_midproduct(B,A,C,true,n0,n1);
}

template<typename Field>
bool launchTest(const Field& F, size_t n, long b, long d, long seed){
	bool ok=true;
	typename Field::RandIter G(F,b,seed);
	typedef PolynomialMatrix<PMType::polfirst,PMStorage::plain,Field> MatrixP;
	//std::cerr<<"Polynomial matrix (polfirst) testing over ";F.write(std::cerr)<<std::endl;
	//ok&=check_matpol_mul<MatrixP> (F,G,n,d);
	//ok&=check_matpol_midp<MatrixP> (F,G,n,d);
	//ok&=check_matpol_midpgen<MatrixP> (F,G,n,d);

	//typedef PolynomialMatrix<PMType::matfirst,PMStorage::plain,Field> PMatrix;
	// std::cerr<<"Polynomial matrix (matfirst) testing:\n";F.write(std::cerr)<<std::endl;
	// check_matpol_mul<PMatrix> (F,G,n,d);
	// check_matpol_midp<PMatrix> (F,G,n,d);

	std::cerr<<"Debugging midpgen for DLP over ";F.write(std::cerr)<<std::endl;
	debug_midpgen_dlp<MatrixP>(F,G);
	return ok;
}

bool runTest(uint64_t n, uint64_t d, long seed){

	bool ok=true;
	// fourier prime < 2^(53--log(n))/2
	{
		size_t bits= (53-integer(n).bitsize())/2;
		RandomFFTPrime Rd(1<<bits,seed);
		integer p = Rd.randomPrime(integer(d).bitsize()+1);

		Givaro::Modular<double> F((int32_t)p);
		ok&=launchTest (F,n,bits,d,seed);

	}

	// normal prime < 2^(53--log(n))/2
	{
		size_t bits= (53-integer(n).bitsize())/2;;
		RandomPrimeIter Rd(bits,seed);
		integer p;
		Rd.random(p);

		Givaro::Modular<double> F((int32_t)p);
		ok&=launchTest (F,n,bits,d,seed);
	}

	// // multi-precision prime
	// {
	// 	size_t bits=114;
	// 	RandomPrimeIter Rd(bits,seed);
	// 	integer p= Rd.random();

	// 	Givaro::Modular<integer> F1(p);
	// 	ok&=launchTest (F1,n,bits,d,seed);
	// 	Givaro::Modular<RecInt::ruint128,RecInt::ruint256> F2(p);
	// 	ok&=launchTest (F2,n,bits,d,seed);

	// }
	// // over the integer
	// {
	// 	Givaro::ZRing<integer> F;
	// 	ok&=launchTest (F,n,128,d,seed);

	// }
	return ok;
}

int main(int argc, char** argv){
	static size_t  n = 16; // matrix dimension
	static size_t  d = 512; // polynomial size
	static long    seed = time(NULL);

	static Argument args[] = {
		{ 'n', "-n N", "Set dimension of test matrices to NxN.", TYPE_INT,     &n },
		{ 'd', "-d D", "Set degree of test matrices to D.", TYPE_INT,     &d },
		{ 's', "-s s", "Set the random seed to a specific value", TYPE_INT, &seed},
		END_OF_ARGUMENTS
	};
	parseArguments (argc, argv, args);

	return (runTest(n,d,seed)? 0: -1);
}

<|endoftext|>