Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 45 additions & 2 deletions crates/mq-lang/modules/module_tests.mq
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,9 @@ def test_toml_parse():
end

def test_toml_to_json():
let result = toml::toml_to_json(toml::toml_parse(toml_input))
| assert_eq(result, "{\"dependencies\":{},\"package\":{\"name\":\"test-package\",\"authors\":[\"Test Author <test@example.com>\"],\"description\":\"A test TOML configuration file\",\"edition\":\"2021\",\"license\":\"MIT\",\"version\":\"1.0.0\"}}")
let parsed = toml::toml_parse(toml_input)
| let result = toml::toml_to_json(parsed)
| assert_eq(json::json_parse(result), parsed)
end

# -- YAML Tests --
Expand Down Expand Up @@ -731,6 +732,48 @@ def test_semver_min():
| assert_eq(semver::semver_to_string(min), "1.0.0")
end

def test_semver_satisfies_range_true():
assert_true(semver::semver_satisfies("1.5.0", ">=1.0.0,<2.0.0"))
end

def test_semver_satisfies_range_false():
assert_false(semver::semver_satisfies("2.0.0", ">=1.0.0,<2.0.0"))
end

def test_semver_satisfies_range_lower_bound_inclusive():
assert_true(semver::semver_satisfies("1.0.0", ">=1.0.0,<2.0.0"))
end

def test_semver_satisfies_exact_match():
assert_true(semver::semver_satisfies("1.2.3", "1.2.3"))
| assert_false(semver::semver_satisfies("1.2.4", "1.2.3"))
end

def test_semver_satisfies_eq_operator():
assert_true(semver::semver_satisfies("1.2.3", "=1.2.3"))
| assert_true(semver::semver_satisfies("1.2.3", "==1.2.3"))
end

def test_semver_satisfies_not_equal():
assert_true(semver::semver_satisfies("1.2.4", "!=1.2.3"))
| assert_false(semver::semver_satisfies("1.2.3", "!=1.2.3"))
end

def test_semver_satisfies_gt_lt():
assert_true(semver::semver_satisfies("1.5.0", ">1.0.0"))
| assert_false(semver::semver_satisfies("1.0.0", ">1.0.0"))
| assert_true(semver::semver_satisfies("1.0.0", "<2.0.0"))
| assert_false(semver::semver_satisfies("2.0.0", "<2.0.0"))
end

def test_semver_satisfies_ignores_whitespace():
assert_true(semver::semver_satisfies("1.5.0", " >= 1.0.0 , < 2.0.0 "))
end

def test_semver_satisfies_with_prerelease():
assert_true(semver::semver_satisfies("1.0.0-alpha", "<1.0.0"))
end

# -- Markdown Builder (md) Tests --

def test_md_h():
Expand Down
42 changes: 42 additions & 0 deletions crates/mq-lang/modules/semver.mq
Original file line number Diff line number Diff line change
Expand Up @@ -173,3 +173,45 @@ end
def semver_min(versions):
fold(versions[1:len(versions)], versions[0], fn(acc, v): if (semver_lt(v, acc)): v else: acc;)
end

# Parses a single version comparator (e.g. ">=1.0.0") into a dict with op and parsed version fields.
def _semver_parse_comparator(comp):
let c = trim(comp)
| if (starts_with(c, ">=")):
{op: ">=", version: semver_parse(trim(ltrimstr(c, ">=")))}
elif (starts_with(c, "<=")):
{op: "<=", version: semver_parse(trim(ltrimstr(c, "<=")))}
elif (starts_with(c, "==")):
{op: "=", version: semver_parse(trim(ltrimstr(c, "==")))}
elif (starts_with(c, "!=")):
{op: "!=", version: semver_parse(trim(ltrimstr(c, "!=")))}
elif (starts_with(c, ">")):
{op: ">", version: semver_parse(trim(ltrimstr(c, ">")))}
elif (starts_with(c, "<")):
{op: "<", version: semver_parse(trim(ltrimstr(c, "<")))}
elif (starts_with(c, "=")):
{op: "=", version: semver_parse(trim(ltrimstr(c, "=")))}
else:
{op: "=", version: semver_parse(c)}
end

# Checks whether a parsed SemVer dict satisfies a single comparator dict produced by `_semver_parse_comparator`.
def _semver_satisfies_comparator(v, cmp):
let op = cmp[:op]
| let cv = cmp[:version]
| if (op == ">="): semver_gte(v, cv)
elif (op == "<="): semver_lte(v, cv)
elif (op == ">"): semver_gt(v, cv)
elif (op == "<"): semver_lt(v, cv)
elif (op == "!="): !semver_eq(v, cv)
else: semver_eq(v, cv)
end

# Returns true if the given version string satisfies every comma-separated comparator in `range`.
# Supported comparators: "=", "==", "!=", ">", ">=", "<", "<=". A bare version (no operator) requires an exact match.
# Example: semver_satisfies("1.5.0", ">=1.0.0,<2.0.0") == true
def semver_satisfies(version, range):
let v = semver_parse(version)
| let comparators = map(split(range, ","), _semver_parse_comparator)
| all(comparators, fn(cmp): _semver_satisfies_comparator(v, cmp);)
end