mirror of
https://github.com/sbrow/thor.git
synced 2026-08-26 11:23:32 -04:00
Compare commits
3 Commits
18733f31d1
...
e7c9ae6c85
| Author | SHA1 | Date | |
|---|---|---|---|
| e7c9ae6c85 | |||
| 62409a423a | |||
| bfd8bd7eff |
@@ -442,8 +442,9 @@ Rust-style error messages with multi-line source context, caret underlines, and
|
|||||||
|
|
||||||
**Exceptions** (no warning):
|
**Exceptions** (no warning):
|
||||||
- `{{.}}` and dot-prefixed names (current context)
|
- `{{.}}` and dot-prefixed names (current context)
|
||||||
- Paths that cross a map (e.g., `params.*` — user-defined namespace)
|
- Paths that cross a map (e.g., `params.*`) — validated for typos via Levenshtein: close matches warn with a suggestion, genuinely absent keys are suppressed silently
|
||||||
- `Maybe(bool)` fields with nil value (field exists, value is nil — distinguished via `struct_has_field`)
|
- `Maybe(bool)` fields with nil value (field exists, value is nil — distinguished via `struct_has_field`)
|
||||||
|
- Found fields whose value is nil/empty (e.g., nil `json.Value` union) — the field exists, looking up sub-keys is valid "not found" behavior
|
||||||
|
|
||||||
**Block override source tracking**: `Block_Override.source: Template` ensures warnings inside block overrides point at the override's source file (e.g., `page.html`), not the parent template (`base.html`).
|
**Block override source tracking**: `Block_Override.source: Template` ensures warnings inside block overrides point at the override's source file (e.g., `page.html`), not the parent template (`base.html`).
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,8 @@
|
|||||||
- [ ] improve json diagnostics.
|
- [ ] improve json diagnostics.
|
||||||
- i.e. "Missing quotes around string", etc.
|
- i.e. "Missing quotes around string", etc.
|
||||||
- [ ] don't use bullshit "sub-tokens", add filters and pipes as proper tokens.
|
- [ ] don't use bullshit "sub-tokens", add filters and pipes as proper tokens.
|
||||||
|
- [ ] Ideas is now in the wrong spot. Date is wrong, and it is showing date
|
||||||
|
when it shouldn't be.
|
||||||
|
|
||||||
## Performance
|
## Performance
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -5,6 +5,7 @@ import ts "treesitter"
|
|||||||
|
|
||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
import "core:log"
|
import "core:log"
|
||||||
|
import "core:encoding/json"
|
||||||
import "core:os"
|
import "core:os"
|
||||||
import "core:strings"
|
import "core:strings"
|
||||||
import "core:time"
|
import "core:time"
|
||||||
@@ -23,10 +24,10 @@ Page :: struct {
|
|||||||
weight: Maybe(int),
|
weight: Maybe(int),
|
||||||
lastmod: string,
|
lastmod: string,
|
||||||
menus: map[string]Menu_Entry,
|
menus: map[string]Menu_Entry,
|
||||||
|
params: json.Value,
|
||||||
content: string,
|
content: string,
|
||||||
og: Open_Graph,
|
og: Open_Graph,
|
||||||
draft: bool,
|
draft: bool,
|
||||||
starred: bool,
|
|
||||||
_is_index: bool `private`,
|
_is_index: bool `private`,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,7 +258,7 @@ load_page :: proc(
|
|||||||
page.weight = fm.weight
|
page.weight = fm.weight
|
||||||
page.lastmod = fm.lastmod
|
page.lastmod = fm.lastmod
|
||||||
page.draft = fm.draft
|
page.draft = fm.draft
|
||||||
page.starred = fm.isStarred
|
page.params = fm.params
|
||||||
|
|
||||||
if section == "" && is_index {
|
if section == "" && is_index {
|
||||||
page.permalink = "/"
|
page.permalink = "/"
|
||||||
|
|||||||
+2
-2
@@ -12,10 +12,10 @@ Frontmatter :: struct {
|
|||||||
publishDate: string,
|
publishDate: string,
|
||||||
weight: Maybe(int),
|
weight: Maybe(int),
|
||||||
menus: json.Value,
|
menus: json.Value,
|
||||||
|
params: json.Value,
|
||||||
layout: string,
|
layout: string,
|
||||||
og: Open_Graph,
|
og: Open_Graph,
|
||||||
draft: bool,
|
draft: bool,
|
||||||
isStarred: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse_frontmatter splits raw file content into a Frontmatter struct and the
|
// parse_frontmatter splits raw file content into a Frontmatter struct and the
|
||||||
@@ -56,12 +56,12 @@ parse_frontmatter :: proc(content: string) -> (fm: Frontmatter, body: string, ok
|
|||||||
fm.publishDate = json_get_string(obj, "publishDate")
|
fm.publishDate = json_get_string(obj, "publishDate")
|
||||||
fm.weight = json_get_int(obj, "weight")
|
fm.weight = json_get_int(obj, "weight")
|
||||||
fm.draft = json_get_bool(obj, "draft")
|
fm.draft = json_get_bool(obj, "draft")
|
||||||
fm.isStarred = json_get_bool(obj, "isStarred")
|
|
||||||
if v, ok := obj["menus"]; ok {
|
if v, ok := obj["menus"]; ok {
|
||||||
fm.menus = v
|
fm.menus = v
|
||||||
}
|
}
|
||||||
fm.layout = json_get_string(obj, "layout")
|
fm.layout = json_get_string(obj, "layout")
|
||||||
fm.og = json_get_open_graph(obj, "og")
|
fm.og = json_get_open_graph(obj, "og")
|
||||||
|
if v, ok := obj["params"]; ok { fm.params = v }
|
||||||
|
|
||||||
ok = true
|
ok = true
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -137,6 +137,22 @@ resolve_name :: proc(name: string, ctx: []any) -> any {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
collect_map_keys :: proc(container: any, allocator := context.temp_allocator) -> []string {
|
||||||
|
val, info := base_value(container)
|
||||||
|
if info == nil do return nil
|
||||||
|
if _, ok := info.variant.(runtime.Type_Info_Map); !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := make([dynamic]string, 0, 4, allocator)
|
||||||
|
it := 0
|
||||||
|
for {
|
||||||
|
key, _ := reflect.iterate_map(val, &it) or_break
|
||||||
|
key_str := key.(string) or_continue
|
||||||
|
append(&out, key_str)
|
||||||
|
}
|
||||||
|
return out[:]
|
||||||
|
}
|
||||||
|
|
||||||
// is_truthy checks mustache truthiness.
|
// is_truthy checks mustache truthiness.
|
||||||
is_truthy :: proc(a: any) -> bool {
|
is_truthy :: proc(a: any) -> bool {
|
||||||
if a == nil {
|
if a == nil {
|
||||||
@@ -302,3 +318,4 @@ write_value :: proc(b: ^strings.Builder, a: any, escape: bool) {
|
|||||||
strings.write_string(b, s[start:])
|
strings.write_string(b, s[start:])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+10
-1
@@ -121,9 +121,18 @@ validate_key_path :: proc(
|
|||||||
for i in 1 ..< part_count {
|
for i in 1 ..< part_count {
|
||||||
v, info := base_value(current)
|
v, info := base_value(current)
|
||||||
if info == nil {
|
if info == nil {
|
||||||
return false, parts[i], nil
|
return true, "", nil
|
||||||
}
|
}
|
||||||
if _, is_map := info.variant.(runtime.Type_Info_Map); is_map {
|
if _, is_map := info.variant.(runtime.Type_Info_Map); is_map {
|
||||||
|
val, found := lookup_in(current, parts[i])
|
||||||
|
if found {
|
||||||
|
current = val
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
available := collect_map_keys(current, allocator)
|
||||||
|
if suggest_correction(available, parts[i]) != "" {
|
||||||
|
return false, parts[i], available
|
||||||
|
}
|
||||||
return true, "", nil
|
return true, "", nil
|
||||||
}
|
}
|
||||||
if _, is_struct := info.variant.(runtime.Type_Info_Struct); is_struct {
|
if _, is_struct := info.variant.(runtime.Type_Info_Struct); is_struct {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#+feature dynamic-literals
|
#+feature dynamic-literals
|
||||||
package mustache
|
package mustache
|
||||||
|
|
||||||
|
import "core:encoding/json"
|
||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
import "core:testing"
|
import "core:testing"
|
||||||
|
|
||||||
@@ -196,3 +197,68 @@ test_warn_no_false_positive_for_valid_keys :: proc(t: ^testing.T) {
|
|||||||
ok, missing, _ := validate_key_path(ctx[:], "name")
|
ok, missing, _ := validate_key_path(ctx[:], "name")
|
||||||
testing.expect_value(t, ok, true)
|
testing.expect_value(t, ok, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- json.Value map crossing tests ---
|
||||||
|
|
||||||
|
JSON_Params_Context :: struct {
|
||||||
|
params: json.Value,
|
||||||
|
}
|
||||||
|
|
||||||
|
@(test)
|
||||||
|
test_validate_key_path_crosses_json_value_map :: proc(t: ^testing.T) {
|
||||||
|
params_map := make(json.Object, context.temp_allocator)
|
||||||
|
params_map["author"] = json.String("Tester")
|
||||||
|
|
||||||
|
data := JSON_Params_Context { params = params_map }
|
||||||
|
ctx := make([dynamic]any, 0, 1, context.temp_allocator)
|
||||||
|
append(&ctx, data)
|
||||||
|
|
||||||
|
ok, missing, _ := validate_key_path(ctx[:], "params.starred")
|
||||||
|
testing.expect(t, ok, "path crossing json.Value map should be ok")
|
||||||
|
testing.expect(t, missing == "", "no missing segment for map crossing")
|
||||||
|
}
|
||||||
|
|
||||||
|
@(test)
|
||||||
|
test_validate_key_path_json_value_map_existing_key :: proc(t: ^testing.T) {
|
||||||
|
params_map := make(json.Object, context.temp_allocator)
|
||||||
|
params_map["author"] = json.String("Tester")
|
||||||
|
|
||||||
|
data := JSON_Params_Context { params = params_map }
|
||||||
|
ctx := make([dynamic]any, 0, 1, context.temp_allocator)
|
||||||
|
append(&ctx, data)
|
||||||
|
|
||||||
|
ok, missing, _ := validate_key_path(ctx[:], "params.author")
|
||||||
|
testing.expect(t, ok, "existing key in json.Value map should be ok")
|
||||||
|
}
|
||||||
|
|
||||||
|
@(test)
|
||||||
|
test_validate_key_path_map_typo :: proc(t: ^testing.T) {
|
||||||
|
params_map := make(json.Object, context.temp_allocator)
|
||||||
|
params_map["author"] = json.String("Tester")
|
||||||
|
params_map["social"] = json.String("")
|
||||||
|
|
||||||
|
data := JSON_Params_Context { params = params_map }
|
||||||
|
ctx := make([dynamic]any, 0, 1, context.temp_allocator)
|
||||||
|
append(&ctx, data)
|
||||||
|
|
||||||
|
ok, missing, available := validate_key_path(ctx[:], "params.authr")
|
||||||
|
testing.expect(t, !ok, "typo of map key should not be ok")
|
||||||
|
testing.expect_value(t, missing, "authr")
|
||||||
|
suggestion := suggest_correction(available, "authr")
|
||||||
|
testing.expect_value(t, suggestion, "author")
|
||||||
|
}
|
||||||
|
|
||||||
|
@(test)
|
||||||
|
test_validate_key_path_map_no_close_match :: proc(t: ^testing.T) {
|
||||||
|
params_map := make(json.Object, context.temp_allocator)
|
||||||
|
params_map["author"] = json.String("Tester")
|
||||||
|
params_map["social"] = json.String("")
|
||||||
|
|
||||||
|
data := JSON_Params_Context { params = params_map }
|
||||||
|
ctx := make([dynamic]any, 0, 1, context.temp_allocator)
|
||||||
|
append(&ctx, data)
|
||||||
|
|
||||||
|
ok, missing, _ := validate_key_path(ctx[:], "params.xyz")
|
||||||
|
testing.expect(t, ok, "unknown key with no close match should be ok (suppressed)")
|
||||||
|
testing.expect(t, missing == "", "no missing segment when suppressed")
|
||||||
|
}
|
||||||
|
|||||||
+21
-3
@@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import "mustache"
|
import "mustache"
|
||||||
|
|
||||||
|
import "core:encoding/json"
|
||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
import "core:log"
|
import "core:log"
|
||||||
import "core:os"
|
import "core:os"
|
||||||
@@ -15,6 +16,7 @@ Template_Context :: struct {
|
|||||||
date_format: string,
|
date_format: string,
|
||||||
timezone: ^datetime.TZ_Region,
|
timezone: ^datetime.TZ_Region,
|
||||||
og: Open_Graph,
|
og: Open_Graph,
|
||||||
|
params: json.Value,
|
||||||
site: Site_Context,
|
site: Site_Context,
|
||||||
menus: map[string][]Menu_Entry,
|
menus: map[string][]Menu_Entry,
|
||||||
page: Page,
|
page: Page,
|
||||||
@@ -117,6 +119,19 @@ to_title_case :: proc(s: string, allocator := context.allocator) -> string {
|
|||||||
return string(out)
|
return string(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
merge_params :: proc(site, page: json.Value) -> json.Value {
|
||||||
|
if page == nil do return site
|
||||||
|
if site == nil do return page
|
||||||
|
site_obj, ok1 := site.(json.Object)
|
||||||
|
page_obj, ok2 := page.(json.Object)
|
||||||
|
if !ok1 do return page
|
||||||
|
if !ok2 do return site
|
||||||
|
merged := make(json.Object, len(site_obj) + len(page_obj), context.temp_allocator)
|
||||||
|
for k, v in site_obj { merged[k] = v }
|
||||||
|
for k, v in page_obj { merged[k] = v }
|
||||||
|
return merged
|
||||||
|
}
|
||||||
|
|
||||||
render_template :: proc(
|
render_template :: proc(
|
||||||
content_tpl: mustache.Template,
|
content_tpl: mustache.Template,
|
||||||
ctx: Template_Context,
|
ctx: Template_Context,
|
||||||
@@ -195,7 +210,7 @@ render_site :: proc(site: ^Site) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
tpl := get_template(&site.vfs, page.layout, &template_cache)
|
tpl := get_template(&site.vfs, page.layout, &template_cache)
|
||||||
html := render_page_html(page, site, tpl, partials, ctx, &seen)
|
html := render_page_html(page, site, tpl, partials, ctx, &errors)
|
||||||
if .Minify in site.features {
|
if .Minify in site.features {
|
||||||
html = minify_html(html)
|
html = minify_html(html)
|
||||||
}
|
}
|
||||||
@@ -224,7 +239,7 @@ render_site :: proc(site: ^Site) {
|
|||||||
section_tpl,
|
section_tpl,
|
||||||
partials,
|
partials,
|
||||||
ctx,
|
ctx,
|
||||||
&seen,
|
&errors,
|
||||||
)
|
)
|
||||||
if .Minify in site.features {
|
if .Minify in site.features {
|
||||||
html = minify_html(html)
|
html = minify_html(html)
|
||||||
@@ -235,7 +250,7 @@ render_site :: proc(site: ^Site) {
|
|||||||
// Render home page
|
// Render home page
|
||||||
if has_home {
|
if has_home {
|
||||||
home_tpl := get_template(&site.vfs, "home", &template_cache)
|
home_tpl := get_template(&site.vfs, "home", &template_cache)
|
||||||
home_html := render_home_html(home, site, home_tpl, partials, ctx, &seen)
|
home_html := render_home_html(home, site, home_tpl, partials, ctx, &errors)
|
||||||
if .Minify in site.features {
|
if .Minify in site.features {
|
||||||
home_html = minify_html(home_html)
|
home_html = minify_html(home_html)
|
||||||
}
|
}
|
||||||
@@ -276,6 +291,7 @@ render_page_html :: proc(
|
|||||||
ctx.title = fmt.tprintf("%s | %s", page.title, site.title)
|
ctx.title = fmt.tprintf("%s | %s", page.title, site.title)
|
||||||
ctx.page = page
|
ctx.page = page
|
||||||
ctx.og = og_for_page(site.og, page)
|
ctx.og = og_for_page(site.og, page)
|
||||||
|
ctx.params = merge_params(site.params, page.params)
|
||||||
return render_template(content_tpl, ctx, partials, seen)
|
return render_template(content_tpl, ctx, partials, seen)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,6 +315,7 @@ render_home_html :: proc(
|
|||||||
ctx.title = site.title
|
ctx.title = site.title
|
||||||
ctx.pages = list_pages
|
ctx.pages = list_pages
|
||||||
ctx.og = og_for_page(site.og, home)
|
ctx.og = og_for_page(site.og, home)
|
||||||
|
ctx.params = merge_params(site.params, home.params)
|
||||||
|
|
||||||
return render_template(content_tpl, ctx, partials, seen)
|
return render_template(content_tpl, ctx, partials, seen)
|
||||||
}
|
}
|
||||||
@@ -340,6 +357,7 @@ render_section :: proc(
|
|||||||
ctx.og.is_article = false
|
ctx.og.is_article = false
|
||||||
}
|
}
|
||||||
ctx.posts = posts
|
ctx.posts = posts
|
||||||
|
ctx.params = merge_params(site.params, ctx.page.params)
|
||||||
return render_template(content_tpl, ctx, partials, seen)
|
return render_template(content_tpl, ctx, partials, seen)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+106
@@ -7,6 +7,8 @@ import "core:fmt"
|
|||||||
import "core:log"
|
import "core:log"
|
||||||
import "core:os"
|
import "core:os"
|
||||||
import "core:testing"
|
import "core:testing"
|
||||||
|
import "core:time/datetime"
|
||||||
|
import "core:time/timezone"
|
||||||
|
|
||||||
write_temp_config :: proc(name: string, content: string) -> string {
|
write_temp_config :: proc(name: string, content: string) -> string {
|
||||||
path := fmt.tprintf("./test_thor_%s.json", name)
|
path := fmt.tprintf("./test_thor_%s.json", name)
|
||||||
@@ -103,6 +105,8 @@ test_load_config_file_partial :: proc(t: ^testing.T) {
|
|||||||
|
|
||||||
@(test)
|
@(test)
|
||||||
test_init_site_defaults_no_config :: proc(t: ^testing.T) {
|
test_init_site_defaults_no_config :: proc(t: ^testing.T) {
|
||||||
|
context.logger = log.nil_logger()
|
||||||
|
|
||||||
site: Site
|
site: Site
|
||||||
args := []string{"thor", "-config:./nonexistent.json"}
|
args := []string{"thor", "-config:./nonexistent.json"}
|
||||||
init_site(&site, args)
|
init_site(&site, args)
|
||||||
@@ -120,6 +124,8 @@ test_init_site_defaults_no_config :: proc(t: ^testing.T) {
|
|||||||
|
|
||||||
@(test)
|
@(test)
|
||||||
test_init_site_config_dir_relative :: proc(t: ^testing.T) {
|
test_init_site_config_dir_relative :: proc(t: ^testing.T) {
|
||||||
|
context.logger = log.nil_logger()
|
||||||
|
|
||||||
site: Site
|
site: Site
|
||||||
args := []string{"thor", "-config:./sub/nonexistent.json"}
|
args := []string{"thor", "-config:./sub/nonexistent.json"}
|
||||||
init_site(&site, args)
|
init_site(&site, args)
|
||||||
@@ -133,6 +139,8 @@ test_init_site_config_dir_relative :: proc(t: ^testing.T) {
|
|||||||
|
|
||||||
@(test)
|
@(test)
|
||||||
test_init_site_flag_overrides_default :: proc(t: ^testing.T) {
|
test_init_site_flag_overrides_default :: proc(t: ^testing.T) {
|
||||||
|
context.logger = log.nil_logger()
|
||||||
|
|
||||||
site: Site
|
site: Site
|
||||||
args := []string{"thor", "-config:./nonexistent.json", "-drafts", "-base-url:https://flag.com"}
|
args := []string{"thor", "-config:./nonexistent.json", "-drafts", "-base-url:https://flag.com"}
|
||||||
init_site(&site, args)
|
init_site(&site, args)
|
||||||
@@ -144,6 +152,8 @@ test_init_site_flag_overrides_default :: proc(t: ^testing.T) {
|
|||||||
|
|
||||||
@(test)
|
@(test)
|
||||||
test_init_site_full_pipeline :: proc(t: ^testing.T) {
|
test_init_site_full_pipeline :: proc(t: ^testing.T) {
|
||||||
|
context.logger = log.nil_logger()
|
||||||
|
|
||||||
path := write_temp_config(
|
path := write_temp_config(
|
||||||
"pipeline",
|
"pipeline",
|
||||||
`{"title":"Pipeline Test","description":"Full","base_url":"https://config.com"}`,
|
`{"title":"Pipeline Test","description":"Full","base_url":"https://config.com"}`,
|
||||||
@@ -163,6 +173,8 @@ test_init_site_full_pipeline :: proc(t: ^testing.T) {
|
|||||||
|
|
||||||
@(test)
|
@(test)
|
||||||
test_init_site_md_enable_disable :: proc(t: ^testing.T) {
|
test_init_site_md_enable_disable :: proc(t: ^testing.T) {
|
||||||
|
context.logger = log.nil_logger()
|
||||||
|
|
||||||
site: Site
|
site: Site
|
||||||
args := []string {
|
args := []string {
|
||||||
"thor",
|
"thor",
|
||||||
@@ -181,6 +193,8 @@ test_init_site_md_enable_disable :: proc(t: ^testing.T) {
|
|||||||
|
|
||||||
@(test)
|
@(test)
|
||||||
test_init_site_config_paths :: proc(t: ^testing.T) {
|
test_init_site_config_paths :: proc(t: ^testing.T) {
|
||||||
|
context.logger = log.nil_logger()
|
||||||
|
|
||||||
path := write_temp_config(
|
path := write_temp_config(
|
||||||
"paths",
|
"paths",
|
||||||
`{
|
`{
|
||||||
@@ -202,3 +216,95 @@ test_init_site_config_paths :: proc(t: ^testing.T) {
|
|||||||
testing.expect_value(t, site.output_dir, "/custom/output")
|
testing.expect_value(t, site.output_dir, "/custom/output")
|
||||||
testing.expect_value(t, site.layouts_dir, "/custom/layouts")
|
testing.expect_value(t, site.layouts_dir, "/custom/layouts")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- merge_params tests ---
|
||||||
|
|
||||||
|
@(test)
|
||||||
|
test_merge_params_both_present :: proc(t: ^testing.T) {
|
||||||
|
site_params, _ := json.parse_string(
|
||||||
|
`{"social": [], "author": "Tester"}`,
|
||||||
|
spec = .JSON,
|
||||||
|
allocator = context.temp_allocator,
|
||||||
|
)
|
||||||
|
page_params, _ := json.parse_string(
|
||||||
|
`{"starred": true}`,
|
||||||
|
spec = .JSON,
|
||||||
|
allocator = context.temp_allocator,
|
||||||
|
)
|
||||||
|
|
||||||
|
merged_val := merge_params(site_params, page_params)
|
||||||
|
merged, ok := merged_val.(json.Object)
|
||||||
|
testing.expect(t, ok, "merged should be a json.Object")
|
||||||
|
|
||||||
|
_, has_social := merged["social"]
|
||||||
|
testing.expect(t, has_social, "site param 'social' should survive merge")
|
||||||
|
|
||||||
|
_, has_author := merged["author"]
|
||||||
|
testing.expect(t, has_author, "site param 'author' should survive merge")
|
||||||
|
|
||||||
|
starred, has_starred := merged["starred"]
|
||||||
|
testing.expect(t, has_starred, "page param 'starred' should be present")
|
||||||
|
starred_bool, _ := starred.(json.Boolean)
|
||||||
|
testing.expect(t, bool(starred_bool), "starred should be true")
|
||||||
|
}
|
||||||
|
|
||||||
|
@(test)
|
||||||
|
test_merge_params_nil_page :: proc(t: ^testing.T) {
|
||||||
|
site_params, _ := json.parse_string(
|
||||||
|
`{"author": "Tester"}`,
|
||||||
|
spec = .JSON,
|
||||||
|
allocator = context.temp_allocator,
|
||||||
|
)
|
||||||
|
|
||||||
|
merged_val := merge_params(site_params, nil)
|
||||||
|
merged, ok := merged_val.(json.Object)
|
||||||
|
testing.expect(t, ok, "should return site params when page is nil")
|
||||||
|
|
||||||
|
_, has_author := merged["author"]
|
||||||
|
testing.expect(t, has_author, "site param should survive")
|
||||||
|
}
|
||||||
|
|
||||||
|
@(test)
|
||||||
|
test_merge_params_nil_site :: proc(t: ^testing.T) {
|
||||||
|
page_params, _ := json.parse_string(
|
||||||
|
`{"starred": true}`,
|
||||||
|
spec = .JSON,
|
||||||
|
allocator = context.temp_allocator,
|
||||||
|
)
|
||||||
|
|
||||||
|
merged_val := merge_params(nil, page_params)
|
||||||
|
merged, ok := merged_val.(json.Object)
|
||||||
|
testing.expect(t, ok, "should return page params when site is nil")
|
||||||
|
|
||||||
|
_, has_starred := merged["starred"]
|
||||||
|
testing.expect(t, has_starred, "page param should survive")
|
||||||
|
}
|
||||||
|
|
||||||
|
@(test)
|
||||||
|
test_merge_params_both_nil :: proc(t: ^testing.T) {
|
||||||
|
merged_val := merge_params(nil, nil)
|
||||||
|
testing.expect(t, merged_val == nil, "both nil should return nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
@(test)
|
||||||
|
test_merge_params_page_overrides_site :: proc(t: ^testing.T) {
|
||||||
|
site_params, _ := json.parse_string(
|
||||||
|
`{"key": "site_value"}`,
|
||||||
|
spec = .JSON,
|
||||||
|
allocator = context.temp_allocator,
|
||||||
|
)
|
||||||
|
page_params, _ := json.parse_string(
|
||||||
|
`{"key": "page_value"}`,
|
||||||
|
spec = .JSON,
|
||||||
|
allocator = context.temp_allocator,
|
||||||
|
)
|
||||||
|
|
||||||
|
merged_val := merge_params(site_params, page_params)
|
||||||
|
merged, ok := merged_val.(json.Object)
|
||||||
|
testing.expect(t, ok)
|
||||||
|
|
||||||
|
val := merged["key"]
|
||||||
|
str, _ := val.(json.String)
|
||||||
|
testing.expect_value(t, string(str), "page_value")
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user