Improved error library by refactorying the sync as two way propagation.
Now one can setup error handler propagation in one way, or two way (sync). The "reset" applies in both way, even if this is a one way propagation to fit current existing usage. Added optional id for the error handlers. Feature renaming according to design changes. Added related autotest cases.
This commit is contained in:
@@ -5,11 +5,13 @@ project
|
|||||||
error = "error.ecf"
|
error = "error.ecf"
|
||||||
|
|
||||||
note
|
note
|
||||||
-- title:
|
title: Error framework
|
||||||
-- description:
|
description: "[
|
||||||
-- tags:
|
Errors and associated handler, to manage errors and also provides a way to synchronize one or many error handlers.
|
||||||
-- license:
|
This is convenient to propagate error from a layer to another without adding unwanted dependencies.
|
||||||
-- copyright:
|
tags: error
|
||||||
-- link[doc]: "Documentation" http://
|
license: Eiffel Forum License v2
|
||||||
|
copyright: Jocelyn Fiat, Eiffel Software and others.
|
||||||
|
link[license]: http://www.eiffel.com/licensing/forum.txt
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -16,13 +16,13 @@ create
|
|||||||
|
|
||||||
feature {NONE} -- Initialization
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
make (a_code: INTEGER; a_name: like name; a_message: detachable like message)
|
make (a_code: INTEGER; a_name: like name; a_message: detachable READABLE_STRING_GENERAL)
|
||||||
-- Initialize `Current'.
|
-- Initialize `Current'.
|
||||||
do
|
do
|
||||||
code := a_code
|
code := a_code
|
||||||
name := a_name
|
name := a_name
|
||||||
if a_message /= Void then
|
if a_message /= Void then
|
||||||
message := a_message
|
message := a_message.as_string_32
|
||||||
else
|
else
|
||||||
message := {STRING_32} "Error: " + a_name + " (code=" + a_code.out + ")"
|
message := {STRING_32} "Error: " + a_name + " (code=" + a_code.out + ")"
|
||||||
end
|
end
|
||||||
@@ -45,7 +45,7 @@ feature -- Visitor
|
|||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2012, Eiffel Software and others"
|
copyright: "2011-2016, Jocelyn Fiat, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
note
|
note
|
||||||
description : "Objects that handle error..."
|
description : "[
|
||||||
|
Error handler or receiver.
|
||||||
|
|
||||||
|
]"
|
||||||
legal: "See notice at end of class."
|
legal: "See notice at end of class."
|
||||||
status: "See notice at end of class."
|
status: "See notice at end of class."
|
||||||
date: "$Date: 2015-10-10 00:55:41 +0200 (sam., 10 oct. 2015) $"
|
date: "$Date: 2015-10-10 00:55:41 +0200 (sam., 10 oct. 2015) $"
|
||||||
@@ -14,7 +17,8 @@ inherit
|
|||||||
DEBUG_OUTPUT
|
DEBUG_OUTPUT
|
||||||
|
|
||||||
create
|
create
|
||||||
make
|
make,
|
||||||
|
make_with_id
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
@@ -25,8 +29,22 @@ feature {NONE} -- Initialization
|
|||||||
create error_added_actions
|
create error_added_actions
|
||||||
end
|
end
|
||||||
|
|
||||||
|
make_with_id (a_id: READABLE_STRING_8)
|
||||||
|
-- Build `Current' with optional id `a_id'.
|
||||||
|
do
|
||||||
|
make
|
||||||
|
if a_id = Void then
|
||||||
|
id := Void
|
||||||
|
else
|
||||||
|
create id.make_from_string (a_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
feature -- Access
|
feature -- Access
|
||||||
|
|
||||||
|
id: detachable IMMUTABLE_STRING_8
|
||||||
|
-- Optional identifier for Current handler.
|
||||||
|
|
||||||
primary_error_code: INTEGER
|
primary_error_code: INTEGER
|
||||||
-- Code of first error in `errors'
|
-- Code of first error in `errors'
|
||||||
require
|
require
|
||||||
@@ -49,6 +67,19 @@ feature -- Status
|
|||||||
Result := errors.count
|
Result := errors.count
|
||||||
end
|
end
|
||||||
|
|
||||||
|
is_synchronizing_with (other: ERROR_HANDLER): BOOLEAN
|
||||||
|
-- Is Current synchronizing with `other'?
|
||||||
|
-- i.e 2 way propagation.
|
||||||
|
do
|
||||||
|
Result := is_propagating_to (other) and other.is_propagating_to (Current)
|
||||||
|
end
|
||||||
|
|
||||||
|
is_propagating_to (other: ERROR_HANDLER): BOOLEAN
|
||||||
|
-- Is Current propagating error to `other'?
|
||||||
|
do
|
||||||
|
Result := attached propagations as lst and then lst.has (other)
|
||||||
|
end
|
||||||
|
|
||||||
feature {ERROR_HANDLER, ERROR_VISITOR} -- Restricted access
|
feature {ERROR_HANDLER, ERROR_VISITOR} -- Restricted access
|
||||||
|
|
||||||
errors: LIST [ERROR]
|
errors: LIST [ERROR]
|
||||||
@@ -64,6 +95,25 @@ feature -- Status report
|
|||||||
else
|
else
|
||||||
Result := "no error"
|
Result := "no error"
|
||||||
end
|
end
|
||||||
|
if attached id as l_id then
|
||||||
|
Result.prepend ("[" + l_id + "] ")
|
||||||
|
end
|
||||||
|
if attached propagations as lst then
|
||||||
|
check not_empty: not lst.is_empty end
|
||||||
|
Result.append_character ('(')
|
||||||
|
Result.append (" -> ")
|
||||||
|
Result.append_integer (lst.count)
|
||||||
|
Result.append_character (':')
|
||||||
|
across
|
||||||
|
lst as ic
|
||||||
|
loop
|
||||||
|
if attached ic.item.id as l_id then
|
||||||
|
Result.append_character (' ')
|
||||||
|
Result.append (l_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
Result.append_character (')')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Events
|
feature -- Events
|
||||||
@@ -77,134 +127,263 @@ feature -- Synchronization
|
|||||||
-- Add synchronization between `h' and `Current'
|
-- Add synchronization between `h' and `Current'
|
||||||
--| the same handler can be added more than once
|
--| the same handler can be added more than once
|
||||||
--| it will be synchronized only once
|
--| it will be synchronized only once
|
||||||
local
|
|
||||||
lst: like synchronized_handlers
|
|
||||||
do
|
do
|
||||||
lst := synchronized_handlers
|
add_propagation (h)
|
||||||
if lst = Void then
|
h.add_propagation (Current)
|
||||||
create {ARRAYED_LIST [ERROR_HANDLER]} lst.make (0)
|
|
||||||
lst.compare_references
|
|
||||||
synchronized_handlers := lst
|
|
||||||
end
|
|
||||||
if lst.has (h) then
|
|
||||||
check attached h.synchronized_handlers as h_lst and then h_lst.has (Current) end
|
|
||||||
else
|
|
||||||
lst.extend (h)
|
|
||||||
h.add_synchronization (Current)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
remove_synchronization (h: ERROR_HANDLER)
|
remove_synchronization (h: ERROR_HANDLER)
|
||||||
-- Remove synchronization between `h' and `Current'
|
-- Remove synchronization between `h' and `Current'
|
||||||
do
|
do
|
||||||
if attached synchronized_handlers as lst and then not lst.is_empty then
|
remove_propagation (h)
|
||||||
synchronized_handlers := Void
|
h.remove_propagation (Current)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- One way synchronization: propagation
|
||||||
|
|
||||||
|
add_propagation (h: ERROR_HANDLER)
|
||||||
|
-- Add propagation from `Current' to `h'.
|
||||||
|
--| the same handler can be added more than once
|
||||||
|
--| it will be synchronized only once
|
||||||
|
local
|
||||||
|
lst: like propagations
|
||||||
|
do
|
||||||
|
h.register_propagator (Current)
|
||||||
|
lst := propagations
|
||||||
|
if lst = Void then
|
||||||
|
create {ARRAYED_LIST [ERROR_HANDLER]} lst.make (0)
|
||||||
|
lst.compare_references
|
||||||
|
propagations := lst
|
||||||
|
end
|
||||||
|
if not lst.has (h) then
|
||||||
|
lst.extend (h)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
remove_propagation (h: ERROR_HANDLER)
|
||||||
|
-- Remove propagation from `Current' to `h'.
|
||||||
|
do
|
||||||
|
if attached propagations as lst and then not lst.is_empty then
|
||||||
lst.prune_all (h)
|
lst.prune_all (h)
|
||||||
|
|
||||||
h.remove_synchronization (Current)
|
|
||||||
|
|
||||||
synchronized_handlers := lst
|
|
||||||
if lst.is_empty then
|
if lst.is_empty then
|
||||||
synchronized_handlers := Void
|
propagations := Void
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
h.unregister_propagator (Current)
|
||||||
end
|
end
|
||||||
|
|
||||||
feature {ERROR_HANDLER} -- Synchronization implementation
|
feature {ERROR_HANDLER} -- Synchronization implementation
|
||||||
|
|
||||||
synchronized_handlers: detachable LIST [ERROR_HANDLER]
|
is_associated_with (h: ERROR_HANDLER): BOOLEAN
|
||||||
-- Synchronized handlers
|
|
||||||
|
|
||||||
synchronize_error_from (e: ERROR; h_lst: LIST [ERROR_HANDLER])
|
|
||||||
-- Called by error_handler during synchronization process
|
|
||||||
-- if `synchronized_handlers' is Void, this means Current is synchronizing
|
|
||||||
-- this is to prevent infinite cycle iteration
|
|
||||||
require
|
|
||||||
not h_lst.has (Current)
|
|
||||||
do
|
do
|
||||||
h_lst.extend (Current)
|
if attached propagators as lst then
|
||||||
|
Result := lst.has (h)
|
||||||
if attached synchronized_handlers as lst then
|
|
||||||
synchronized_handlers := Void
|
|
||||||
add_error (e)
|
|
||||||
across
|
|
||||||
lst as c
|
|
||||||
loop
|
|
||||||
if not h_lst.has (c.item) then
|
|
||||||
c.item.synchronize_error_from (e, h_lst)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
synchronized_handlers := lst
|
|
||||||
else
|
|
||||||
-- In synchronization
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
synchronize_reset_from (h_lst: LIST [ERROR_HANDLER])
|
register_propagator (h: ERROR_HANDLER)
|
||||||
-- Called by error_handler during synchronization process
|
local
|
||||||
-- if `synchronized_handlers' is Void, this means Current is synchronizing
|
lst: like propagators
|
||||||
-- this is to prevent infinite cycle iteration
|
do
|
||||||
|
lst := propagators
|
||||||
|
if lst = Void then
|
||||||
|
create {ARRAYED_LIST [ERROR_HANDLER]} lst.make (1)
|
||||||
|
propagators := lst
|
||||||
|
end
|
||||||
|
if not lst.has (h) then
|
||||||
|
lst.extend (h)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
unregister_propagator (h: ERROR_HANDLER)
|
||||||
|
local
|
||||||
|
lst: like propagators
|
||||||
|
do
|
||||||
|
lst := propagators
|
||||||
|
if lst /= Void then
|
||||||
|
lst.prune_all (h)
|
||||||
|
if lst.is_empty then
|
||||||
|
propagators := Void
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
propagators: detachable LIST [ERROR_HANDLER]
|
||||||
|
-- Handlers propagating to Current.
|
||||||
|
-- Needed for `reset'.
|
||||||
|
|
||||||
|
propagations: detachable LIST [ERROR_HANDLER]
|
||||||
|
-- Handlers receiving the propagation.
|
||||||
|
|
||||||
|
propagate_error_addition (e: ERROR; h_lst: LIST [ERROR_HANDLER])
|
||||||
|
-- Called by error_handler during synchronization process.
|
||||||
|
-- To prevent infinite cycle, if Currently synchronizing, the `propagations' is Void.
|
||||||
require
|
require
|
||||||
not h_lst.has (Current)
|
not h_lst.has (Current)
|
||||||
|
local
|
||||||
|
lst: like propagations
|
||||||
do
|
do
|
||||||
h_lst.extend (Current)
|
h_lst.extend (Current)
|
||||||
if attached synchronized_handlers as lst then
|
lst := propagations
|
||||||
synchronized_handlers := Void
|
propagations := Void
|
||||||
reset
|
add_error (e)
|
||||||
|
|
||||||
|
if lst /= Void then
|
||||||
across
|
across
|
||||||
lst as c
|
lst as c
|
||||||
loop
|
loop
|
||||||
if not h_lst.has (c.item) then
|
if not h_lst.has (c.item) then
|
||||||
c.item.synchronize_reset_from (h_lst)
|
c.item.propagate_error_addition (e, h_lst)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
synchronized_handlers := lst
|
propagations := lst
|
||||||
else
|
else
|
||||||
-- In synchronization
|
--| propagating
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
propagate_errors_removal (errs: ITERABLE [ERROR]; h_lst: LIST [ERROR_HANDLER])
|
||||||
|
-- Called by error_handler during synchronization process.
|
||||||
|
-- To prevent infinite cycle, if Currently synchronizing, the `propagations' is Void.
|
||||||
|
require
|
||||||
|
not h_lst.has (Current)
|
||||||
|
local
|
||||||
|
lst: like propagations
|
||||||
|
do
|
||||||
|
h_lst.extend (Current)
|
||||||
|
lst := propagations
|
||||||
|
propagations := Void
|
||||||
|
across
|
||||||
|
errs as ic
|
||||||
|
loop
|
||||||
|
-- Question: should we use remove_error (ic.item) ?
|
||||||
|
errors.prune_all (ic.item)
|
||||||
|
end
|
||||||
|
|
||||||
|
if lst /= Void then
|
||||||
|
across
|
||||||
|
lst as c
|
||||||
|
loop
|
||||||
|
if not h_lst.has (c.item) then
|
||||||
|
c.item.propagate_errors_removal (errs, h_lst)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
propagations := lst
|
||||||
|
else
|
||||||
|
--| propagating
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
backpropagate_reset (h_lst: LIST [ERROR_HANDLER])
|
||||||
|
-- Called by error_handler during propagation process.
|
||||||
|
-- To prevent infinite cycle, if Currently synchronizing, the `propagations' is Void.
|
||||||
|
require
|
||||||
|
not h_lst.has (Current)
|
||||||
|
local
|
||||||
|
lst: like propagations
|
||||||
|
do
|
||||||
|
h_lst.extend (Current)
|
||||||
|
lst := propagations
|
||||||
|
propagations := Void
|
||||||
|
reset
|
||||||
|
if lst /= Void then
|
||||||
|
across
|
||||||
|
lst as c
|
||||||
|
loop
|
||||||
|
if not h_lst.has (c.item) then
|
||||||
|
-- Reset c.item, even if this is not a two way synchronization!
|
||||||
|
c.item.backpropagate_reset (h_lst)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
propagations := lst
|
||||||
|
else
|
||||||
|
--| propagating
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
feature {NONE} -- Event: implementation
|
feature {NONE} -- Event: implementation
|
||||||
|
|
||||||
on_error_added (e: ERROR)
|
on_error_added (e: ERROR)
|
||||||
-- Error `e' was just added
|
-- Error `e' was just added.
|
||||||
local
|
local
|
||||||
sync_list: LINKED_LIST [ERROR_HANDLER]
|
sync_list: ARRAYED_LIST [ERROR_HANDLER]
|
||||||
do
|
do
|
||||||
error_added_actions.call ([e])
|
error_added_actions.call ([e])
|
||||||
if attached synchronized_handlers as lst then
|
if attached propagations as lst then
|
||||||
synchronized_handlers := Void
|
propagations := Void
|
||||||
create sync_list.make
|
create sync_list.make (1 + lst.count)
|
||||||
sync_list.extend (Current)
|
sync_list.extend (Current)
|
||||||
across
|
across
|
||||||
lst as c
|
lst as c
|
||||||
loop
|
loop
|
||||||
if not sync_list.has (c.item) then
|
if not sync_list.has (c.item) then
|
||||||
c.item.synchronize_error_from (e, sync_list)
|
c.item.propagate_error_addition (e, sync_list)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
synchronized_handlers := lst
|
propagations := lst
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
on_errors_removed (errs: ITERABLE [ERROR])
|
||||||
|
-- Errors `errs' were just removed.
|
||||||
|
local
|
||||||
|
sync_list: ARRAYED_LIST [ERROR_HANDLER]
|
||||||
|
lst: like propagations
|
||||||
|
do
|
||||||
|
lst := propagations
|
||||||
|
if lst /= Void then
|
||||||
|
propagations := Void
|
||||||
|
create sync_list.make (1 + lst.count)
|
||||||
|
sync_list.extend (Current)
|
||||||
|
across
|
||||||
|
lst as c
|
||||||
|
loop
|
||||||
|
if not sync_list.has (c.item) then
|
||||||
|
c.item.propagate_errors_removal (errs, sync_list)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
propagations := lst
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
on_reset
|
on_reset
|
||||||
-- `reset' was just called
|
-- `reset' was just called
|
||||||
local
|
local
|
||||||
sync_list: LINKED_LIST [ERROR_HANDLER]
|
sync_list: detachable ARRAYED_LIST [ERROR_HANDLER]
|
||||||
|
lst: detachable LIST [ERROR_HANDLER]
|
||||||
do
|
do
|
||||||
if attached synchronized_handlers as lst then
|
lst := propagators
|
||||||
synchronized_handlers := Void
|
if lst /= Void then
|
||||||
create sync_list.make
|
create sync_list.make (1 + lst.count)
|
||||||
sync_list.extend (Current)
|
sync_list.extend (Current)
|
||||||
|
|
||||||
|
propagators := Void
|
||||||
across
|
across
|
||||||
lst as c
|
lst as c
|
||||||
loop
|
loop
|
||||||
if not sync_list.has (c.item) then
|
if not sync_list.has (c.item) then
|
||||||
c.item.synchronize_reset_from (sync_list)
|
c.item.backpropagate_reset (sync_list)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
synchronized_handlers := lst
|
propagators := lst
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- lst := propagations
|
||||||
|
-- propagations := Void
|
||||||
|
-- if lst /= Void then
|
||||||
|
-- if sync_list = Void then
|
||||||
|
-- create sync_list.make (1 + lst.count)
|
||||||
|
-- sync_list.extend (Current)
|
||||||
|
-- end
|
||||||
|
-- across
|
||||||
|
-- lst as c
|
||||||
|
-- loop
|
||||||
|
-- if not sync_list.has (c.item) then
|
||||||
|
-- c.item.synchronize_reset_from (sync_list)
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
-- propagations := lst
|
||||||
|
-- end
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Basic operation
|
feature -- Basic operation
|
||||||
@@ -216,7 +395,17 @@ feature -- Basic operation
|
|||||||
on_error_added (a_error)
|
on_error_added (a_error)
|
||||||
end
|
end
|
||||||
|
|
||||||
add_error_details, add_custom_error (a_code: INTEGER; a_name: STRING; a_message: detachable READABLE_STRING_32)
|
remove_error (a_error: ERROR)
|
||||||
|
-- Remove `a_error' from the stack of error.
|
||||||
|
-- And also propagate error removal.
|
||||||
|
do
|
||||||
|
if propagations /= Void then
|
||||||
|
on_errors_removed (<<a_error>>)
|
||||||
|
end
|
||||||
|
errors.prune_all (a_error)
|
||||||
|
end
|
||||||
|
|
||||||
|
add_error_details, add_custom_error (a_code: INTEGER; a_name: STRING; a_message: detachable READABLE_STRING_GENERAL)
|
||||||
-- Add custom error to the stack of error
|
-- Add custom error to the stack of error
|
||||||
local
|
local
|
||||||
e: ERROR_CUSTOM
|
e: ERROR_CUSTOM
|
||||||
@@ -285,11 +474,22 @@ feature -- Element changes
|
|||||||
end
|
end
|
||||||
|
|
||||||
reset
|
reset
|
||||||
-- Reset error handler
|
-- Reset Current error handler.
|
||||||
|
-- And also reset recursively error handlers propagating to Current (i.e the propagators).
|
||||||
|
do
|
||||||
|
errors.wipe_out
|
||||||
|
on_reset
|
||||||
|
ensure
|
||||||
|
has_no_error: not has_error
|
||||||
|
count = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
remove_all_errors
|
||||||
|
-- Remove all errors.
|
||||||
do
|
do
|
||||||
if errors.count > 0 then
|
if errors.count > 0 then
|
||||||
|
on_errors_removed (errors)
|
||||||
errors.wipe_out
|
errors.wipe_out
|
||||||
on_reset
|
|
||||||
end
|
end
|
||||||
ensure
|
ensure
|
||||||
has_no_error: not has_error
|
has_no_error: not has_error
|
||||||
@@ -297,22 +497,26 @@ feature -- Element changes
|
|||||||
end
|
end
|
||||||
|
|
||||||
destroy
|
destroy
|
||||||
-- Destroy Current, and remove any synchronization
|
-- Destroy Current, and remove any propagations (in the two directions).
|
||||||
do
|
do
|
||||||
error_added_actions.wipe_out
|
error_added_actions.wipe_out
|
||||||
if attached synchronized_handlers as lst then
|
if attached propagations as lst then
|
||||||
|
propagations := Void
|
||||||
across
|
across
|
||||||
lst as c
|
lst as c
|
||||||
loop
|
loop
|
||||||
c.item.remove_synchronization (Current)
|
c.item.remove_synchronization (Current)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
synchronized_handlers := Void
|
|
||||||
reset
|
reset
|
||||||
end
|
end
|
||||||
|
|
||||||
|
invariant
|
||||||
|
propagations_not_empty: attached propagations as lst implies not lst.is_empty
|
||||||
|
propagators_not_empty: attached propagators as lst implies not lst.is_empty
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2014, Jocelyn Fiat, Eiffel Software and others"
|
copyright: "2011-2016, Jocelyn Fiat, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -38,6 +38,30 @@ feature -- Test routines
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test_propagation_2
|
||||||
|
note
|
||||||
|
testing: "error"
|
||||||
|
local
|
||||||
|
h1, h2: ERROR_HANDLER
|
||||||
|
-- cl: CELL [INTEGER]
|
||||||
|
do
|
||||||
|
create h1.make_with_id ("h1")
|
||||||
|
create h2.make_with_id ("h2")
|
||||||
|
|
||||||
|
h1.add_propagation (h2)
|
||||||
|
|
||||||
|
h1.add_custom_error (123, "abc", "abc error occurred")
|
||||||
|
h1.add_custom_error (456, "def", "def error occurred")
|
||||||
|
|
||||||
|
assert ("has 2 errors", h1.count = 2 and h2.count = h1.count)
|
||||||
|
|
||||||
|
h2.add_custom_error (789, "ghi", "error occurred only for h2")
|
||||||
|
assert ("h1 has 2 errors, h2 has 3 errors", h1.count = 2 and h2.count = h1.count + 1)
|
||||||
|
|
||||||
|
h1.remove_all_errors
|
||||||
|
assert ("remove all error from h1, and one remaining on h2", h1.count = 0 and h2.count = 1)
|
||||||
|
end
|
||||||
|
|
||||||
test_sync_2
|
test_sync_2
|
||||||
note
|
note
|
||||||
testing: "error"
|
testing: "error"
|
||||||
@@ -50,7 +74,7 @@ feature -- Test routines
|
|||||||
h1.add_synchronization (h2)
|
h1.add_synchronization (h2)
|
||||||
|
|
||||||
h1.add_custom_error (123, "abc", "abc error occurred")
|
h1.add_custom_error (123, "abc", "abc error occurred")
|
||||||
h1.add_custom_error (456, "abc", "abc error occurred")
|
h1.add_custom_error (456, "def", "def error occurred")
|
||||||
|
|
||||||
assert ("has 2 errors", h1.count = 2 and h2.count = h1.count)
|
assert ("has 2 errors", h1.count = 2 and h2.count = h1.count)
|
||||||
|
|
||||||
@@ -108,6 +132,62 @@ feature -- Test routines
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test_tree_propag
|
||||||
|
--| Testing tree propagation
|
||||||
|
--|
|
||||||
|
--| |-----> batch ..........
|
||||||
|
--| | :
|
||||||
|
--| db ---> core ---> app ----> ui :
|
||||||
|
--| : : : : :
|
||||||
|
--| :.......:.........:........:...:.....> logger
|
||||||
|
--|
|
||||||
|
note
|
||||||
|
testing: "error"
|
||||||
|
local
|
||||||
|
hdb, hcore, happ, hui, hlog, hbat: ERROR_HANDLER
|
||||||
|
do
|
||||||
|
create hdb.make_with_id ("db")
|
||||||
|
create hcore.make_with_id ("core")
|
||||||
|
create happ.make_with_id ("app")
|
||||||
|
create hui.make_with_id ("ui")
|
||||||
|
create hlog.make_with_id ("logger")
|
||||||
|
create hbat.make_with_id ("batch")
|
||||||
|
|
||||||
|
hdb.add_propagation (hcore)
|
||||||
|
hcore.add_propagation (happ)
|
||||||
|
hcore.add_propagation (hbat)
|
||||||
|
happ.add_propagation (hui)
|
||||||
|
|
||||||
|
hdb.add_propagation (hlog)
|
||||||
|
hcore.add_propagation (hlog)
|
||||||
|
happ.add_propagation (hlog)
|
||||||
|
hui.add_propagation (hlog)
|
||||||
|
hbat.add_propagation (hlog)
|
||||||
|
|
||||||
|
hdb.add_custom_error (1, "db", "database connection error")
|
||||||
|
hdb.add_custom_error (2, "db", "database query error")
|
||||||
|
assert ("2 errors", hdb.count = 2 and hcore.count = 2 and happ.count = 2 and hui.count = 2 and hlog.count = 2)
|
||||||
|
hcore.add_custom_error (11, "core", "core error")
|
||||||
|
assert ("3 errors", hdb.count = 2 and hcore.count = 3 and happ.count = 3 and hui.count = 3 and hlog.count = 3)
|
||||||
|
happ.add_custom_error (101, "app", "app issue")
|
||||||
|
assert ("2 errors", hdb.count = 2 and hcore.count = 3 and happ.count = 4 and hui.count = 4 and hlog.count = 4)
|
||||||
|
hui.add_custom_error (1001, "ui", "user interface trouble")
|
||||||
|
assert ("2 errors", hdb.count = 2 and hcore.count = 3 and happ.count = 4 and hui.count = 5 and hlog.count = 5)
|
||||||
|
|
||||||
|
assert ("hbat", hbat.count = 3 and hlog.count = 5)
|
||||||
|
hbat.add_custom_error (10001, "bat", "Batch issue")
|
||||||
|
assert ("2 errors", hdb.count = 2 and hcore.count = 3 and happ.count = 4 and hui.count = 5 and hbat.count = 4 and hlog.count = 6)
|
||||||
|
hbat.remove_all_errors
|
||||||
|
assert ("2 errors", hdb.count = 2 and hcore.count = 3 and happ.count = 4 and hui.count = 5 and hbat.count = 0 and hlog.count = 2)
|
||||||
|
|
||||||
|
hui.remove_all_errors
|
||||||
|
assert ("2 errors", hdb.count = 2 and hcore.count = 3 and happ.count = 4 and hui.count = 0 and hlog.count = 0)
|
||||||
|
|
||||||
|
hdb.reset
|
||||||
|
assert ("no more errors", hdb.count = 0 and hcore.count = 3 and happ.count = 4 and hui.count = 0 and hlog.count = 0)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
test_remove_sync
|
test_remove_sync
|
||||||
note
|
note
|
||||||
testing: "error"
|
testing: "error"
|
||||||
@@ -145,9 +225,9 @@ feature -- Test routines
|
|||||||
h1, h2, h3: ERROR_HANDLER
|
h1, h2, h3: ERROR_HANDLER
|
||||||
-- cl: CELL [INTEGER]
|
-- cl: CELL [INTEGER]
|
||||||
do
|
do
|
||||||
create h1.make
|
create h1.make_with_id ("h1")
|
||||||
create h2.make
|
create h2.make_with_id ("h2")
|
||||||
create h3.make
|
create h3.make_with_id ("h3")
|
||||||
|
|
||||||
h1.add_synchronization (h2)
|
h1.add_synchronization (h2)
|
||||||
h2.add_synchronization (h3)
|
h2.add_synchronization (h3)
|
||||||
|
|||||||
@@ -1,17 +1,21 @@
|
|||||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-9-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-9-0 http://www.eiffel.com/developers/xml/configuration-1-9-0.xsd" name="error_tests" uuid="54F59BB2-AD49-42C7-ABAA-B60765F4F926">
|
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-15-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-15-0 http://www.eiffel.com/developers/xml/configuration-1-15-0.xsd" name="error_tests" uuid="54F59BB2-AD49-42C7-ABAA-B60765F4F926">
|
||||||
<target name="error_tests">
|
<target name="error_tests">
|
||||||
<root class="TEST_ERROR" feature="default_create"/>
|
<root class="TEST_ERROR" feature="default_create"/>
|
||||||
<file_rule>
|
<file_rule>
|
||||||
<exclude>/.git$</exclude>
|
<exclude>/.git$</exclude>
|
||||||
<exclude>/EIFGENs$</exclude>
|
|
||||||
<exclude>/.svn$</exclude>
|
<exclude>/.svn$</exclude>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
</file_rule>
|
</file_rule>
|
||||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
|
<option warning="true" full_class_checking="true" is_attached_by_default="true" is_obsolete_routine_type="true" void_safety="transitional" syntax="transitional">
|
||||||
<assertions precondition="true"/>
|
<assertions precondition="true" postcondition="true" check="true" invariant="true"/>
|
||||||
</option>
|
</option>
|
||||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||||
<library name="error" location="..\error-safe.ecf" readonly="false"/>
|
<library name="error" location="..\error-safe.ecf" readonly="false">
|
||||||
|
<option>
|
||||||
|
<assertions precondition="true" postcondition="true" check="true" invariant="true" supplier_precondition="true"/>
|
||||||
|
</option>
|
||||||
|
</library>
|
||||||
<library name="testing" location="$ISE_LIBRARY\library\testing\testing-safe.ecf"/>
|
<library name="testing" location="$ISE_LIBRARY\library\testing\testing-safe.ecf"/>
|
||||||
<tests name="tests" location=".\"/>
|
<tests name="tests" location=".\"/>
|
||||||
</target>
|
</target>
|
||||||
|
|||||||
Reference in New Issue
Block a user