aboutsummaryrefslogtreecommitdiff
path: root/tools/integration/game_discovery_test.cpp
blob: a5cfe0fc5a95baea29932e18ce57e5c04278a9d6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// SPDX-License-Identifier: GPL-3.0-or-later

#include "qt_common/game_list/discovery.h"
#include <chrono>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <source_location>

namespace fs = std::filesystem;

void Check(bool condition,
           std::source_location location = std::source_location::current()) {
  if (!condition) {
    std::cerr << "Game discovery regression failed at line " << location.line()
              << '\n';
    std::exit(1);
  }
}

int main() {
  const auto temp = fs::temp_directory_path();
  const auto root =
      temp / ("eglantine-discovery-" +
              std::to_string(
                  std::chrono::steady_clock::now().time_since_epoch().count()));
  Check(fs::equivalent(root.parent_path(), temp) && fs::create_directory(root));
  struct Cleanup {
    fs::path path;
    ~Cleanup() { fs::remove_all(path); }
  } cleanup{root};
  const auto touch = [](const fs::path &path) {
    fs::create_directories(path.parent_path());
    std::ofstream{path}.put('x');
  };
  const auto dump = [&](const fs::path &path) {
    touch(path / "exefs/main");
    touch(path / "exefs/main.npdm");
  };
  const auto supported = [](const fs::path &path) {
    return path.filename() == "main" || path.extension() == ".nsp";
  };
  const auto discover = [&](const fs::path &path, bool deep) {
    return GameListDiscovery::Discover(path, deep, supported,
                                       [] { return false; });
  };

  const auto game = root / fs::path{u8"MKW-églantine"};
  dump(game / "base");
  dump(game / "updates/0100000000000800");
  for (unsigned i = 0; i < 400; ++i) {
    touch(game / "base/romfs/assets" / std::to_string(i) / "false-game.nsp");
  }
  touch(root / "standalone.nsp");
  touch(root / "unrelated/romfs/actual-game.nsp");

  const auto deep = discover(root, true);
  Check(deep.files.size() == 4 && deep.skipped_romfs == 1 && deep.errors == 0);
  Check(deep.directories.size() < 20);
  Check(discover(root, false).files.size() == 3);
  Check(discover(game / "base", false).files.size() == 1);
  Check(discover(game / "base/exefs", false).files.size() == 1);
  Check(discover(root / "missing", true).files.empty());

  touch(root / "incomplete/exefs/main");
  touch(root / "incomplete/romfs/actual-game.nsp");
  Check(discover(root, true).files.size() == 6);

  unsigned calls{};
  const auto cancelled = GameListDiscovery::Discover(
      root, true, supported, [&] { return ++calls > 3; });
  Check(calls < 10 && cancelled.directories.size() <= 1);
  std::cout << "Discovery: loose layouts, payload pruning, Unicode, shallow "
               "scans and cancellation passed\n";
}