aboutsummaryrefslogtreecommitdiff
path: root/aoc2023/build/packages/adglent/src/showtime/internal/common
diff options
context:
space:
mode:
authorJ.J <thechairman@thechairman.info>2024-05-30 21:50:02 -0400
committerJ.J <thechairman@thechairman.info>2024-05-30 21:50:02 -0400
commit612fd986ab1e00b6d34dc1937136250e08e89325 (patch)
treea3c93952040c6afdf348b5831619a45db7ba0a2e /aoc2023/build/packages/adglent/src/showtime/internal/common
parent231c2b688d1e6cf0846d46e883da30e042a9c6cf (diff)
downloadgleam_aoc-612fd986ab1e00b6d34dc1937136250e08e89325.tar.gz
gleam_aoc-612fd986ab1e00b6d34dc1937136250e08e89325.zip
cleanup
Diffstat (limited to 'aoc2023/build/packages/adglent/src/showtime/internal/common')
-rw-r--r--aoc2023/build/packages/adglent/src/showtime/internal/common/cli.gleam5
-rw-r--r--aoc2023/build/packages/adglent/src/showtime/internal/common/common_event_handler.gleam101
-rw-r--r--aoc2023/build/packages/adglent/src/showtime/internal/common/test_result.gleam119
-rw-r--r--aoc2023/build/packages/adglent/src/showtime/internal/common/test_suite.gleam63
4 files changed, 288 insertions, 0 deletions
diff --git a/aoc2023/build/packages/adglent/src/showtime/internal/common/cli.gleam b/aoc2023/build/packages/adglent/src/showtime/internal/common/cli.gleam
new file mode 100644
index 0000000..1c03211
--- /dev/null
+++ b/aoc2023/build/packages/adglent/src/showtime/internal/common/cli.gleam
@@ -0,0 +1,5 @@
+pub type Capture {
+ Yes
+ No
+ Mixed
+}
diff --git a/aoc2023/build/packages/adglent/src/showtime/internal/common/common_event_handler.gleam b/aoc2023/build/packages/adglent/src/showtime/internal/common/common_event_handler.gleam
new file mode 100644
index 0000000..b90af14
--- /dev/null
+++ b/aoc2023/build/packages/adglent/src/showtime/internal/common/common_event_handler.gleam
@@ -0,0 +1,101 @@
+import gleam/map.{type Map}
+import showtime/internal/common/test_suite.{
+ type TestEvent, type TestRun, CompletedTestRun, EndTest, EndTestRun,
+ EndTestSuite, OngoingTestRun, StartTest, StartTestRun, StartTestSuite,
+}
+
+pub type TestState {
+ NotStarted
+ Running
+ Finished(num_modules: Int)
+}
+
+pub type HandlerState {
+ HandlerState(
+ test_state: TestState,
+ num_done: Int,
+ events: Map(String, Map(String, TestRun)),
+ )
+}
+
+// This is the common event-handler (shared between erlang/JS targets)
+// The main strategy is to collect the test-results in a map of maps:
+// module_name ->
+// test_name -> test_result
+// It will also keep track of if it is running (i.e. did it receive the EndTestRun)
+// so that the caller can determine when to print test-results
+pub fn handle_event(
+ msg: TestEvent,
+ system_time: fn() -> Int,
+ state: HandlerState,
+) {
+ let test_state = state.test_state
+ let num_done = state.num_done
+ let events = state.events
+ let #(updated_test_state, updated_num_done, updated_events) = case msg {
+ StartTestRun -> #(Running, num_done, events)
+ StartTestSuite(module) -> {
+ let maybe_module_events = map.get(events, module.name)
+ let new_events = case maybe_module_events {
+ Ok(_) -> events
+ Error(_) ->
+ events
+ |> map.insert(module.name, map.new())
+ }
+ #(test_state, num_done, new_events)
+ }
+ StartTest(module, test) -> {
+ let current_time = system_time()
+ let maybe_module_events = map.get(events, module.name)
+ let new_events = case maybe_module_events {
+ Ok(module_events) -> {
+ let maybe_test_event = map.get(module_events, test.name)
+ case maybe_test_event {
+ Error(_) ->
+ events
+ |> map.insert(
+ module.name,
+ module_events
+ |> map.insert(test.name, OngoingTestRun(test, current_time)),
+ )
+ Ok(_) -> events
+ }
+ }
+ Error(_) -> events
+ }
+ #(test_state, num_done, new_events)
+ }
+ EndTest(module, test, result) -> {
+ let current_time = system_time()
+ let maybe_module_events = map.get(events, module.name)
+ let new_events = case maybe_module_events {
+ Ok(module_events) -> {
+ let maybe_test_run =
+ module_events
+ |> map.get(test.name)
+ let updated_module_events = case maybe_test_run {
+ Ok(OngoingTestRun(test_function, started_at)) ->
+ module_events
+ |> map.insert(
+ test.name,
+ CompletedTestRun(
+ test_function,
+ current_time - started_at,
+ result,
+ ),
+ )
+ Error(_) -> module_events
+ }
+ events
+ |> map.insert(module.name, updated_module_events)
+ }
+ Error(_) -> events
+ }
+ #(test_state, num_done, new_events)
+ }
+ EndTestSuite(_) -> #(test_state, num_done + 1, events)
+ EndTestRun(num_modules) -> #(Finished(num_modules), num_done, events)
+ _ -> #(Running, num_done, events)
+ }
+ HandlerState(updated_test_state, updated_num_done, updated_events)
+}
diff --git a/aoc2023/build/packages/adglent/src/showtime/internal/common/test_result.gleam b/aoc2023/build/packages/adglent/src/showtime/internal/common/test_result.gleam
new file mode 100644
index 0000000..a1d6bd9
--- /dev/null
+++ b/aoc2023/build/packages/adglent/src/showtime/internal/common/test_result.gleam
@@ -0,0 +1,119 @@
+import gleam/dynamic.{type Dynamic}
+import gleam/map.{type Map}
+
+// These are all the types used for test-results
+// NOTE: These are heavily used in the erlang/js ffi:s
+// so any changes here are likely to break the ffi:s unless
+// the corresponding change is introduced there
+//
+// Futhermore this has some erlang related names that should
+// probably be cleaned up, but it is used by both the ffi:s
+
+// Currently only one reason, but could be possible to support
+// more reasons in the future
+pub type IgnoreReason {
+ Ignore
+}
+
+// This is the return value from running the test-function
+// or ignored if the test was ignored
+pub type TestReturn {
+ TestFunctionReturn(value: Dynamic, output_buffer: List(String))
+ Ignored(reason: IgnoreReason)
+}
+
+// All data about an exception in the test function is captured
+// in this type.
+// This is also where the data about the assertions will end up (in reason)
+pub type Exception {
+ ErlangException(
+ class: Class,
+ reason: Reason,
+ stacktrace: TraceList,
+ output_buffer: List(String),
+ )
+}
+
+// Alias for the test-result which is either a TestResult (passed test, ignored or a test-definition)
+// or an Exception (failed test)
+pub type TestResult =
+ Result(TestReturn, Exception)
+
+// Reason is either an assert equal (which is if the error was produced by gleeunit should)
+// TODO: Add other asserts
+// or it is a gleam error meaning that is was produced by showtime should
+// TODO: Rename GleamError to ShowtimeError
+pub type Reason {
+ AssertEqual(details: List(ReasonDetail))
+ AssertNotEqual(details: List(ReasonDetail))
+ AssertMatch(details: List(ReasonDetail))
+ GleamError(details: GleamErrorDetail)
+ GleamAssert(value: Dynamic, line_no: Int)
+ GenericException(value: Dynamic)
+}
+
+// ReasonDetail is the union-type used in erlang-exceptions where the reason
+// is a list of such details
+pub type ReasonDetail {
+ Module(name: String)
+ ReasonLine(line_no: Int)
+ Expression(expression: String)
+ Expected(value: Dynamic)
+ Value(value: Dynamic)
+ Pattern(pattern: String)
+}
+
+// Gleam error detail is produced by showtime should and will hold all the information
+// about the assertion (both expected and got)
+pub type GleamErrorDetail {
+ LetAssert(
+ module: String,
+ function: String,
+ line_no: Int,
+ message: String,
+ value: Dynamic,
+ )
+}
+
+// Class is a part of standard erlang exceptions, but also used on js-side
+// TODO: Extend to include a JS specific constructor
+pub type Class {
+ ErlangError
+ Exit
+ Throw
+}
+
+// The trace list is part of the standard erlang exception, but is also
+// emulated on js-side.
+// TODO: Maybe we need a js-version that contain some js-specific trace-elements
+pub type TraceList {
+ TraceList(traces: List(Trace))
+}
+
+// Trace are the elements in the trace list in an erlang exception
+// TODO: Maybe add a js-specific trace (since arity is not really a js attribute)
+pub type Trace {
+ Trace(function: String, arity: Arity, extra_info: List(ExtraInfo))
+ TraceModule(
+ module: String,
+ function: String,
+ arity: Arity,
+ extra_info: List(ExtraInfo),
+ )
+}
+
+// Extra info holds information about the file and line
+// as well as some dynamic data in a map
+// This is currently not used in the reporter
+pub type ExtraInfo {
+ ErrorInfo(error_info: Map(Dynamic, Dynamic))
+ File(filename: String)
+ Line(line_no: Int)
+}
+
+// Arity is the erlang type for arity
+// Can be either a number, or a list of arguments
+pub type Arity {
+ Num(arity: Int)
+ ArgList(arg_list: List(Dynamic))
+}
diff --git a/aoc2023/build/packages/adglent/src/showtime/internal/common/test_suite.gleam b/aoc2023/build/packages/adglent/src/showtime/internal/common/test_suite.gleam
new file mode 100644
index 0000000..eb58d64
--- /dev/null
+++ b/aoc2023/build/packages/adglent/src/showtime/internal/common/test_suite.gleam
@@ -0,0 +1,63 @@
+import gleam/option.{type Option}
+import showtime/internal/common/test_result.{type TestResult}
+import showtime/internal/common/cli.{type Capture}
+
+// The state (and result) of a test function
+pub type TestRun {
+ OngoingTestRun(test_function: TestFunction, started_at: Int)
+ CompletedTestRun(
+ test_function: TestFunction,
+ total_time: Int,
+ result: TestResult,
+ )
+}
+
+// A test module (found by discovery)
+pub type TestModule {
+ TestModule(name: String, path: Option(String))
+}
+
+// A test function
+pub type TestFunction {
+ TestFunction(name: String)
+}
+
+// A test suite is a test module together with the test functions
+// that were collected from that module
+pub type TestSuite {
+ TestSuite(module: TestModule, tests: List(TestFunction))
+}
+
+// Test event for the event handler
+pub type TestEvent {
+ StartTestRun
+ StartTestSuite(test_module: TestModule)
+ StartTest(test_module: TestModule, test_function: TestFunction)
+ EndTest(
+ test_module: TestModule,
+ test_function: TestFunction,
+ result: TestResult,
+ )
+ EndTestSuite(test_module: TestModule)
+ EndTestRun(num_modules: Int)
+}
+
+// Interface for the module handler
+pub type TestModuleHandler =
+ fn(TestModule) -> Nil
+
+// Interface for the event handler
+pub type TestEventHandler =
+ fn(TestEvent) -> Nil
+
+// Interface for the module collector
+pub type ModuleCollector =
+ fn(TestModuleHandler) -> List(TestModule)
+
+// Interface for the function collector
+pub type TestFunctionCollector =
+ fn(TestModule) -> TestSuite
+
+// Interface for the test runner
+pub type TestRunner =
+ fn(TestSuite, TestEventHandler, List(String), Capture) -> Nil