109 lines
4.0 KiB
Ruby
109 lines
4.0 KiB
Ruby
|
|
require_relative "test_helper"
|
||
|
|
require "tmpdir"
|
||
|
|
require "fileutils"
|
||
|
|
require "json"
|
||
|
|
|
||
|
|
class ProjectIndexTest < Minitest::Test
|
||
|
|
def with_index
|
||
|
|
Dir.mktmpdir do |dir|
|
||
|
|
path = File.join(dir, ".cc-os", "projects.json")
|
||
|
|
yield Backlog::ProjectIndex.new(path: path, today: -> { "2026-07-13" }), path
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def test_missing_file_reads_as_empty
|
||
|
|
with_index do |index, _path|
|
||
|
|
assert_equal({}, index.all)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def test_corrupt_file_reads_as_empty_and_is_not_clobbered_by_reads
|
||
|
|
with_index do |index, path|
|
||
|
|
FileUtils.mkdir_p(File.dirname(path))
|
||
|
|
File.write(path, "{not json")
|
||
|
|
assert_equal({}, index.all)
|
||
|
|
assert_equal "{not json", File.read(path) # read paths never rewrite
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def test_upsert_creates_row_with_updated_at
|
||
|
|
with_index do |index, path|
|
||
|
|
index.upsert(path: "/repos/foo", name: "foo", tracker: "planka:foo", remote: nil)
|
||
|
|
data = JSON.parse(File.read(path))
|
||
|
|
assert_equal 1, data["version"]
|
||
|
|
row = data["projects"]["/repos/foo"]
|
||
|
|
assert_equal "foo", row["name"]
|
||
|
|
assert_equal "planka:foo", row["tracker"]
|
||
|
|
assert_nil row["remote"]
|
||
|
|
assert_equal "2026-07-13", row["updated_at"]
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def test_upsert_updates_existing_row_keyed_by_path
|
||
|
|
with_index do |index, _path|
|
||
|
|
index.upsert(path: "/repos/foo", name: "foo", tracker: "planka:foo", remote: nil)
|
||
|
|
index.upsert(path: "/repos/foo", name: "foo", tracker: "github:me/foo", remote: "r")
|
||
|
|
assert_equal 1, index.all.size
|
||
|
|
assert_equal "github:me/foo", index.all["/repos/foo"]["tracker"]
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def test_name_collision_two_paths_same_basename_keeps_both
|
||
|
|
with_index do |index, _path|
|
||
|
|
index.upsert(path: "/a/foo", name: "foo", tracker: "planka:foo", remote: nil)
|
||
|
|
index.upsert(path: "/b/foo", name: "foo", tracker: "github:me/foo", remote: nil)
|
||
|
|
assert_equal %w[/a/foo /b/foo], index.all.keys.sort
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def test_upsert_over_corrupt_file_leaves_valid_json_and_no_temp_files
|
||
|
|
with_index do |index, path|
|
||
|
|
FileUtils.mkdir_p(File.dirname(path))
|
||
|
|
File.write(path, "{not json")
|
||
|
|
index.upsert(path: "/repos/foo", name: "foo", tracker: "repo:.", remote: nil)
|
||
|
|
data = JSON.parse(File.read(path))
|
||
|
|
assert_equal ["/repos/foo"], data["projects"].keys
|
||
|
|
leftovers = Dir.children(File.dirname(path)).reject { |f| f == "projects.json" }
|
||
|
|
assert_empty leftovers, "atomic write left temp files: #{leftovers}"
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def test_default_path_honors_cc_os_home_override
|
||
|
|
path = Backlog::ProjectIndex.default_path(env: { "CC_OS_HOME" => "/tmp/x", "HOME" => "/home/y" })
|
||
|
|
assert_equal "/tmp/x/projects.json", path
|
||
|
|
end
|
||
|
|
|
||
|
|
def test_default_path_falls_back_to_home
|
||
|
|
path = Backlog::ProjectIndex.default_path(env: { "HOME" => "/home/y" })
|
||
|
|
assert_equal "/home/y/.cc-os/projects.json", path
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
class ProjectsCliContractTest < Minitest::Test
|
||
|
|
BIN = File.expand_path("../bin/os-backlog", __dir__)
|
||
|
|
|
||
|
|
# config-write must upsert the index (redirected via CC_OS_HOME so the
|
||
|
|
# real ~/.cc-os is never touched), and `projects` must always emit a
|
||
|
|
# top-level "projects" key — even when the index is empty.
|
||
|
|
def test_config_write_upserts_index_and_projects_lists_it
|
||
|
|
Dir.mktmpdir do |home|
|
||
|
|
Dir.mktmpdir do |repo|
|
||
|
|
env = "CC_OS_HOME=#{home} HOME=#{home}"
|
||
|
|
out = Dir.chdir(repo) { `#{env} ruby #{BIN} projects 2>/dev/null` }
|
||
|
|
assert_equal({ "projects" => {} }, JSON.parse(out))
|
||
|
|
|
||
|
|
Dir.chdir(repo) { `#{env} ruby #{BIN} config-write planka:demo 2>/dev/null` }
|
||
|
|
out = Dir.chdir(repo) { `#{env} ruby #{BIN} projects 2>/dev/null` }
|
||
|
|
projects = JSON.parse(out)["projects"]
|
||
|
|
assert_equal 1, projects.size
|
||
|
|
row = projects.values.first
|
||
|
|
assert_equal "planka:demo", row["tracker"]
|
||
|
|
assert_equal File.basename(File.realpath(repo)), row["name"]
|
||
|
|
|
||
|
|
filtered = Dir.chdir(repo) { `#{env} ruby #{BIN} projects no-such-name 2>/dev/null` }
|
||
|
|
assert_equal({}, JSON.parse(filtered)["projects"])
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|